diff --git a/sys/conf/files b/sys/conf/files
index e7f520a6430c..2fb96e87e17f 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -732,6 +732,8 @@ geom/geom_sunlabel.c	optional geom
 gnu/ext2fs/ext2_alloc.c		optional ext2fs \
 	warning "kernel contains GPL contaminated ext2fs file system"
 gnu/ext2fs/ext2_balloc.c	optional ext2fs
+gnu/ext2fs/ext2_bmap.c		optional ext2fs
+gnu/ext2fs/ext2_ihash.c		optional ext2fs
 gnu/ext2fs/ext2_inode.c		optional ext2fs
 gnu/ext2fs/ext2_inode_cnv.c	optional ext2fs
 gnu/ext2fs/ext2_linux_balloc.c	optional ext2fs
diff --git a/sys/gnu/ext2fs/ext2_alloc.c b/sys/gnu/ext2fs/ext2_alloc.c
index b9c40d37b9e1..585c5cdb4632 100644
--- a/sys/gnu/ext2fs/ext2_alloc.c
+++ b/sys/gnu/ext2fs/ext2_alloc.c
@@ -40,8 +40,6 @@
  * $FreeBSD$
  */
 
-#include "opt_quota.h"
-
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/conf.h>
@@ -50,11 +48,8 @@
 #include <sys/mount.h>
 #include <sys/syslog.h>
 
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-#include <ufs/ufs/ufsmount.h>
-
+#include <gnu/ext2fs/inode.h>
+#include <gnu/ext2fs/ext2_mount.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
 #include <gnu/ext2fs/fs.h>
@@ -108,9 +103,6 @@ ext2_alloc(ip, lbn, bpref, size, cred, bnp)
 {
 	register struct ext2_sb_info *fs;
 	daddr_t bno;
-#if QUOTA
-	int error;
-#endif
 	
 	*bnp = 0;
 	fs = ip->i_e2fs;
@@ -128,10 +120,6 @@ ext2_alloc(ip, lbn, bpref, size, cred, bnp)
 	if (cred->cr_uid != 0 && 
 		fs->s_es->s_free_blocks_count < fs->s_es->s_r_blocks_count)
 		goto nospace;
-#if QUOTA
-	if ((error = chkdq(ip, (long)btodb(size), cred, 0)) != 0)
-		return (error);
-#endif
 	if (bpref >= fs->s_es->s_blocks_count)
 		bpref = 0;
 	/* call the Linux code */
@@ -179,12 +167,6 @@ ext2_alloc(ip, lbn, bpref, size, cred, bnp)
 		*bnp = bno;
 		return (0);
 	}
-#if QUOTA
-	/*
-	 * Restore user's disk quota because allocation failed.
-	 */
-	(void) chkdq(ip, (long)-btodb(size), cred, FORCE);
-#endif
 nospace:
 	ext2_fserr(fs, cred->cr_uid, "file system full");
 	uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
@@ -342,7 +324,7 @@ return ENOSPC;
 	} else {
 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
 		if (!doasyncfree)
-			UFS_UPDATE(vp, 1);
+			ext2_update(vp, 1);
 	}
 	if (ssize < len)
 		if (doasyncfree)
@@ -401,7 +383,7 @@ ext2_valloc(pvp, mode, cred, vpp)
 		goto noinodes;
 	error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp);
 	if (error) {
-		UFS_VFREE(pvp, ino, mode);
+		ext2_vfree(pvp, ino, mode);
 		return (error);
 	}
 	ip = VTOI(*vpp);
diff --git a/sys/gnu/ext2fs/ext2_balloc.c b/sys/gnu/ext2fs/ext2_balloc.c
index 275849fcec52..252a29792527 100644
--- a/sys/gnu/ext2fs/ext2_balloc.c
+++ b/sys/gnu/ext2fs/ext2_balloc.c
@@ -48,10 +48,7 @@
 #include <sys/ucred.h>
 #include <sys/vnode.h>
 
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-#include <ufs/ufs/ufs_extern.h>
-
+#include <gnu/ext2fs/inode.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
 #include <gnu/ext2fs/fs.h>
@@ -164,11 +161,11 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
 	 * Determine the number of levels of indirection.
 	 */
 	pref = 0;
-	if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0)
+	if ((error = ext2_getlbns(vp, bn, indirs, &num)) != 0)
 		return(error);
 #if DIAGNOSTIC
 	if (num < 1)
-		panic ("ext2_balloc: ufs_getlbns returned indirect block");
+		panic ("ext2_balloc: ext2_getlbns returned indirect block");
 #endif
 	/*
 	 * Fetch the first indirect block allocating if necessary.
diff --git a/sys/gnu/ext2fs/ext2_extern.h b/sys/gnu/ext2fs/ext2_extern.h
index 8df829b369a7..505fefd97c56 100644
--- a/sys/gnu/ext2fs/ext2_extern.h
+++ b/sys/gnu/ext2fs/ext2_extern.h
@@ -43,8 +43,8 @@
 #ifndef _SYS_GNU_EXT2FS_EXT2_EXTERN_H_
 #define	_SYS_GNU_EXT2FS_EXT2_EXTERN_H_
 
-struct dinode;
 struct ext2_inode;
+struct indir;
 struct inode;
 struct mount;
 struct vfsconf;
@@ -58,7 +58,18 @@ int	ext2_blkatoff(struct vnode *, off_t, char **, struct buf **);
 void	ext2_blkfree(struct inode *, daddr_t, long);
 daddr_t	ext2_blkpref(struct inode *, daddr_t, int, daddr_t *, daddr_t);
 int	ext2_bmap(struct vop_bmap_args *);
-int	ext2_init(struct vfsconf *);
+int	ext2_bmaparray(struct vnode *, daddr_t, daddr_t *, int *, int *);
+void	ext2_dirbad(struct inode *ip, doff_t offset, char *how);
+void	ext2_ei2i(struct ext2_inode *, struct inode *);
+int	ext2_getlbns(struct vnode *, daddr_t, struct indir *, int *);
+void	ext2_i2ei(struct inode *, struct ext2_inode *);
+int	ext2_ihashget(dev_t, ino_t, int, struct vnode **);
+void	ext2_ihashinit(void);
+void	ext2_ihashins(struct inode *);
+struct vnode *
+	ext2_ihashlookup(dev_t, ino_t);
+void	ext2_ihashrem(struct inode *);
+void	ext2_itimes(struct vnode *vp);
 int	ext2_reallocblks(struct vop_reallocblks_args *);
 int	ext2_reclaim(struct vop_reclaim_args *);
 void	ext2_setblock(struct ext2_sb_info *, u_char *, daddr_t);
@@ -66,9 +77,9 @@ int	ext2_truncate(struct vnode *, off_t, int, struct ucred *, struct thread *);
 int	ext2_update(struct vnode *, int);
 int	ext2_valloc(struct vnode *, int, struct ucred *, struct vnode **);
 int	ext2_vfree(struct vnode *, ino_t, int);
+int	ext2_vinit(struct mount *, vop_t **, vop_t **, struct vnode **vpp);
 int 	ext2_lookup(struct vop_cachedlookup_args *);
 int 	ext2_readdir(struct vop_readdir_args *);
-void	ext2_print_dinode(struct dinode *);
 void	ext2_print_inode(struct inode *);
 int	ext2_direnter(struct inode *, 
 		struct vnode *, struct componentname *);
@@ -89,15 +100,13 @@ unsigned long ext2_count_free(struct buf *map, unsigned int numchars);
 void	ext2_free_blocks(struct mount *mp, unsigned long block,
 	    unsigned long count);
 void	ext2_free_inode(struct inode * inode);
-void	ext2_ei2di(struct ext2_inode *ei, struct dinode *di);
-void	ext2_di2ei(struct dinode *di, struct ext2_inode *ei);
 void	mark_buffer_dirty(struct buf *bh);
 
-/*
- * This macro allows the ufs code to distinguish between an EXT2 and a
- * non-ext2(FFS/LFS) vnode.
- */
-#define  IS_EXT2_VNODE(vp) (vp->v_mount->mnt_stat.f_type == MOUNT_EXT2FS)
+/* Flags to low-level allocation routines. */
+#define B_CLRBUF	0x01	/* Request allocated buffer be cleared. */
+#define B_SYNC		0x02	/* Do all allocations synchronously. */
+#define B_METAONLY	0x04	/* Return indirect block buffer. */
+#define B_NOWAIT	0x08	/* do not sleep to await lock */
 
 extern vop_t **ext2_vnodeop_p;
 extern vop_t **ext2_specop_p;
diff --git a/sys/gnu/ext2fs/ext2_fs.h b/sys/gnu/ext2fs/ext2_fs.h
index b5e9f4a92573..29435937181b 100644
--- a/sys/gnu/ext2fs/ext2_fs.h
+++ b/sys/gnu/ext2fs/ext2_fs.h
@@ -38,19 +38,6 @@
 #define umode_t mode_t
 #define loff_t  off_t
 
-/* the Linux implementation of EXT2 stores some information about
- * an inode in a ext2_inode_info structure which is part of the incore
- * inode in Linux
- * I decided to use the "spare" fields instead - we'll see how this
- * works out
- */
-
-#define i_block_group		i_spare[0]
-#define i_next_alloc_block	i_spare[1]
-#define i_next_alloc_goal	i_spare[2]
-#define i_prealloc_block	i_din.di_spare[0]
-#define i_prealloc_count	i_din.di_spare[1]
-
 /*
  * The second extended filesystem constants/structures
  */
@@ -263,14 +250,6 @@ struct ext2_group_desc
 #define	EXT2_IOC_GETVERSION		_IOR('v', 1, long)
 #define	EXT2_IOC_SETVERSION		_IOW('v', 2, long)
 
-/*
- * Only declare `struct ext2_inode' if <ufs/ufs/inode.h> hasn't made things
- * difficult by #defining i_mode and other struct members.  The details of
- * the struct are only needed in ext2_inode_cnv.c where the ext2fs on-disk
- * inode is converted to a ufs in-core inode.
- */
-#ifndef i_mode
-
 /*
  * Structure of an inode on the disk
  */
@@ -351,8 +330,6 @@ struct ext2_inode {
 #define i_reserved2	osd2.masix2.m_i_reserved2
 #endif
 
-#endif /* i_mode */
-
 /*
  * File system states
  */
diff --git a/sys/gnu/ext2fs/ext2_inode.c b/sys/gnu/ext2fs/ext2_inode.c
index 2f0aed472f09..207778c84f88 100644
--- a/sys/gnu/ext2fs/ext2_inode.c
+++ b/sys/gnu/ext2fs/ext2_inode.c
@@ -40,8 +40,6 @@
  * $FreeBSD$
  */
 
-#include "opt_quota.h"
-
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/mount.h>
@@ -53,12 +51,8 @@
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-#include <ufs/ufs/ufsmount.h>
-#include <ufs/ufs/ufs_extern.h>
-
+#include <gnu/ext2fs/inode.h>
+#include <gnu/ext2fs/ext2_mount.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
 #include <gnu/ext2fs/fs.h>
@@ -67,12 +61,6 @@
 static int ext2_indirtrunc(struct inode *, daddr_t, daddr_t, daddr_t, int,
 	    long *);
 
-int
-ext2_init(struct vfsconf *vfsp)
-{
-	return (ufs_init(vfsp));
-}
-
 /*
  * Update the access, modified, and inode change times as specified by the
  * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively.  Write the inode
@@ -92,7 +80,7 @@ ext2_update(vp, waitfor)
 	struct inode *ip;
 	int error;
 
-	ufs_itimes(vp);
+	ext2_itimes(vp);
 	ip = VTOI(vp);
 	if ((ip->i_flag & IN_MODIFIED) == 0)
 		return (0);
@@ -106,8 +94,8 @@ ext2_update(vp, waitfor)
 		brelse(bp);
 		return (error);
 	}
-	ext2_di2ei( &ip->i_din, (struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE *
-	    ino_to_fsbo(fs, ip->i_number)));
+	ext2_i2ei(ip, (struct ext2_inode *)((char *)bp->b_data +
+	    EXT2_INODE_SIZE * ino_to_fsbo(fs, ip->i_number)));
 /*
 	if (waitfor && (vp->v_mount->mnt_flag & MNT_ASYNC) == 0)
 		return (bwrite(bp));
@@ -166,16 +154,12 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
 		bzero((char *)&oip->i_shortlink, (u_int)oip->i_size);
 		oip->i_size = 0;
 		oip->i_flag |= IN_CHANGE | IN_UPDATE;
-		return (UFS_UPDATE(ovp, 1));
+		return (ext2_update(ovp, 1));
 	}
 	if (oip->i_size == length) {
 		oip->i_flag |= IN_CHANGE | IN_UPDATE;
-		return (UFS_UPDATE(ovp, 0));
+		return (ext2_update(ovp, 0));
 	}
-#if QUOTA
-	if ((error = getinoquota(oip)) != 0)
-		return (error);
-#endif
 	fs = oip->i_e2fs;
 	osize = oip->i_size;
 	ext2_discard_prealloc(oip);
@@ -200,7 +184,7 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
 		else
 			bawrite(bp);
 		oip->i_flag |= IN_CHANGE | IN_UPDATE;
-		return (UFS_UPDATE(ovp, 1));
+		return (ext2_update(ovp, 1));
 	}
 	/*
 	 * Shorten the size of the file. If the file is not being
@@ -256,7 +240,7 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
 	for (i = NDADDR - 1; i > lastblock; i--)
 		oip->i_db[i] = 0;
 	oip->i_flag |= IN_CHANGE | IN_UPDATE;
-	allerror = UFS_UPDATE(ovp, 1);
+	allerror = ext2_update(ovp, 1);
 
 	/*
 	 * Having written the new inode to disk, save its new configuration
@@ -361,9 +345,6 @@ done:
 		oip->i_blocks = 0;
 	oip->i_flag |= IN_CHANGE;
 	vnode_pager_setsize(ovp, length);
-#if QUOTA
-	(void) chkdq(oip, -blocksreleased, NOCRED, 0);
-#endif
 	return (allerror);
 }
 
@@ -488,9 +469,86 @@ int
 ext2_inactive(ap)
         struct vop_inactive_args /* {
 		struct vnode *a_vp;
+		struct thread *a_td;
 	} */ *ap;
 {
-	ext2_discard_prealloc(VTOI(ap->a_vp));
-	return ufs_inactive(ap);
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
+	struct thread *td = ap->a_td;
+	int mode, error = 0;
+
+	ext2_discard_prealloc(ip);
+	if (prtactive && vp->v_usecount != 0)
+		vprint("ext2_inactive: pushing active", vp);
+
+	/*
+	 * Ignore inodes related to stale file handles.
+	 */
+	if (ip->i_mode == 0)
+		goto out;
+	if (ip->i_nlink <= 0) {
+		(void) vn_write_suspend_wait(vp, NULL, V_WAIT);
+		error = ext2_truncate(vp, (off_t)0, 0, NOCRED, td);
+		ip->i_rdev = 0;
+		mode = ip->i_mode;
+		ip->i_mode = 0;
+		ip->i_flag |= IN_CHANGE | IN_UPDATE;
+		ext2_vfree(vp, ip->i_number, mode);
+	}
+	if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) {
+		if ((ip->i_flag & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 &&
+		    vn_write_suspend_wait(vp, NULL, V_NOWAIT)) {
+			ip->i_flag &= ~IN_ACCESS;
+		} else {
+			(void) vn_write_suspend_wait(vp, NULL, V_WAIT);
+			ext2_update(vp, 0);
+		}
+	}
+out:
+	VOP_UNLOCK(vp, 0, td);
+	/*
+	 * If we are done with the inode, reclaim it
+	 * so that it can be reused immediately.
+	 */
+	if (ip->i_mode == 0)
+		vrecycle(vp, NULL, td);
+	return (error);
 }
 
+/*
+ * Reclaim an inode so that it can be used for other purposes.
+ */
+int
+ext2_reclaim(ap)
+	struct vop_reclaim_args /* {
+		struct vnode *a_vp;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct inode *ip;
+	struct vnode *vp = ap->a_vp;
+
+	if (prtactive && vp->v_usecount != 0)
+		vprint("ufs_reclaim: pushing active", vp);
+	ip = VTOI(vp);
+	if (ip->i_flag & IN_LAZYMOD) {
+		ip->i_flag |= IN_MODIFIED;
+		ext2_update(vp, 0);
+	}
+	/*
+	 * Remove the inode from its hash chain.
+	 */
+	ext2_ihashrem(ip);
+	/*
+	 * Purge old data structures associated with the inode.
+	 */
+	cache_purge(vp);
+	if (ip->i_devvp) {
+		vrele(ip->i_devvp);
+		ip->i_devvp = 0;
+	}
+	lockdestroy(&vp->v_lock);
+	FREE(vp->v_data, M_EXT2NODE);
+	vp->v_data = 0;
+	return (0);
+}
diff --git a/sys/gnu/ext2fs/ext2_inode_cnv.c b/sys/gnu/ext2fs/ext2_inode_cnv.c
index 3e8e0ff73445..d64e5498776b 100644
--- a/sys/gnu/ext2fs/ext2_inode_cnv.c
+++ b/sys/gnu/ext2fs/ext2_inode_cnv.c
@@ -23,7 +23,7 @@
  */
 
 /*
- * routines to convert on disk ext2 inodes in dinodes and back
+ * routines to convert on disk ext2 inodes into inodes and back
  */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -31,130 +31,101 @@
 #include <sys/stat.h>
 #include <sys/vnode.h>
 
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-
-/*
- * Undo the definitions in <ufs/ufs/inode.h> that would destroy the include
- * of <gnu/ext2fs/ext2_fs.h>.
- */
-#undef i_atime
-#undef i_blocks
-#undef i_ctime
-#undef i_db
-#undef i_flags
-#undef i_gen
-#undef i_gid
-#undef i_ib
-#undef i_mode
-#undef i_mtime
-#undef i_nlink
-#undef i_rdev
-#undef i_shortlink
-#undef i_size
-#undef i_uid
-
+#include <gnu/ext2fs/inode.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_extern.h>
 
-void
-ext2_print_dinode( di )
-	struct dinode *di;
-{
-	int i;
-	printf( /* "Inode: %5d" */
-		" Type: %10s Mode: 0x%o Flags: 0x%x  Version: %d\n",
-		"n/a", di->di_mode, di->di_flags, di->di_gen);
-	printf( "User: %5lu Group: %5lu  Size: %lu\n",
-		(unsigned long)di->di_uid, (unsigned long)di->di_gid,
-		(unsigned long)di->di_size);
-	printf( "Links: %3d Blockcount: %d\n",
-		di->di_nlink, di->di_blocks);
-	printf( "ctime: 0x%x", di->di_ctime); 
-	printf( "atime: 0x%x", di->di_atime); 
-	printf( "mtime: 0x%x", di->di_mtime); 
-	printf( "BLOCKS: ");
-	for(i=0; i < (di->di_blocks <= 24 ? ((di->di_blocks+1)/2): 12); i++)
-		printf("%d ", di->di_db[i]);
-	printf("\n");
-}
-
 void
 ext2_print_inode( in )
 	struct inode *in;
 {
+	int i;
+
 	printf( "Inode: %5d", in->i_number);
-	ext2_print_dinode(&in->i_din);
+	printf( /* "Inode: %5d" */
+		" Type: %10s Mode: 0x%o Flags: 0x%x  Version: %d\n",
+		"n/a", in->i_mode, in->i_flags, in->i_gen);
+	printf( "User: %5lu Group: %5lu  Size: %lu\n",
+		(unsigned long)in->i_uid, (unsigned long)in->i_gid,
+		(unsigned long)in->i_size);
+	printf( "Links: %3d Blockcount: %d\n",
+		in->i_nlink, in->i_blocks);
+	printf( "ctime: 0x%x", in->i_ctime);
+	printf( "atime: 0x%x", in->i_atime);
+	printf( "mtime: 0x%x", in->i_mtime);
+	printf( "BLOCKS: ");
+	for(i=0; i < (in->i_blocks <= 24 ? ((in->i_blocks+1)/2): 12); i++)
+		printf("%d ", in->i_db[i]);
+	printf("\n");
 }
 
 /*
- *	raw ext2 inode to dinode
+ *	raw ext2 inode to inode
  */
 void
-ext2_ei2di(ei, di)
-        struct ext2_inode *ei;
-        struct dinode *di;
+ext2_ei2i(ei, ip)
+	struct ext2_inode *ei;
+	struct inode *ip;
 {
-        int     i;
+        int i;
 
-        di->di_nlink    = ei->i_links_count;
+	ip->i_nlink = ei->i_links_count;
 	/* Godmar thinks - if the link count is zero, then the inode is
 	   unused - according to ext2 standards. Ufs marks this fact
 	   by setting i_mode to zero - why ?
 	   I can see that this might lead to problems in an undelete.
 	*/
-	di->di_mode     = ei->i_links_count ? ei->i_mode : 0;
-        di->di_size     = ei->i_size;
-        di->di_atime	= ei->i_atime;
-        di->di_mtime	= ei->i_mtime;
-        di->di_ctime	= ei->i_ctime;
-        di->di_flags    = 0;
-        di->di_flags    |= (ei->i_flags & EXT2_APPEND_FL) ? APPEND : 0;
-        di->di_flags    |= (ei->i_flags & EXT2_IMMUTABLE_FL) ? IMMUTABLE : 0;
-        di->di_blocks   = ei->i_blocks;
-        di->di_gen      = ei->i_generation;
-        di->di_uid      = ei->i_uid;
-        di->di_gid      = ei->i_gid;
+	ip->i_mode = ei->i_links_count ? ei->i_mode : 0;
+	ip->i_size = ei->i_size;
+	ip->i_atime = ei->i_atime;
+	ip->i_mtime = ei->i_mtime;
+	ip->i_ctime = ei->i_ctime;
+	ip->i_flags = 0;
+	ip->i_flags |= (ei->i_flags & EXT2_APPEND_FL) ? APPEND : 0;
+	ip->i_flags |= (ei->i_flags & EXT2_IMMUTABLE_FL) ? IMMUTABLE : 0;
+	ip->i_blocks = ei->i_blocks;
+	ip->i_gen = ei->i_generation;
+	ip->i_uid = ei->i_uid;
+	ip->i_gid = ei->i_gid;
 	/* XXX use memcpy */
-        for(i = 0; i < NDADDR; i++)
-                di->di_db[i] = ei->i_block[i];
-        for(i = 0; i < NIADDR; i++)
-                di->di_ib[i] = ei->i_block[EXT2_NDIR_BLOCKS + i];
+	for(i = 0; i < NDADDR; i++)
+		ip->i_db[i] = ei->i_block[i];
+	for(i = 0; i < NIADDR; i++)
+		ip->i_ib[i] = ei->i_block[EXT2_NDIR_BLOCKS + i];
 }
 
 /*
- *	dinode to raw ext2 inode
+ *	inode to raw ext2 inode
  */
 void
-ext2_di2ei(di, ei)
-        struct dinode *di;
-        struct ext2_inode *ei;
+ext2_i2ei(ip, ei)
+	struct inode *ip;
+	struct ext2_inode *ei;
 {
-        int     i;
+	int i;
 
-        ei->i_mode              = di->di_mode;
-        ei->i_links_count       = di->di_nlink;
+	ei->i_mode = ip->i_mode;
+        ei->i_links_count = ip->i_nlink;
 	/* 
 	   Godmar thinks: if dtime is nonzero, ext2 says this inode
 	   has been deleted, this would correspond to a zero link count
 	 */
-        ei->i_dtime             = ei->i_links_count ? 0 : di->di_mtime;
-        ei->i_size              = di->di_size;
-        ei->i_atime             = di->di_atime;
-        ei->i_mtime             = di->di_mtime;
-        ei->i_ctime             = di->di_ctime;
-        ei->i_flags             = di->di_flags;
-        ei->i_flags    		= 0;
-        ei->i_flags    		|= (di->di_flags & APPEND) ? EXT2_APPEND_FL: 0;
-        ei->i_flags    		|= (di->di_flags & IMMUTABLE) 
-							? EXT2_IMMUTABLE_FL: 0;
-        ei->i_blocks            = di->di_blocks;
-        ei->i_generation        = di->di_gen;
-        ei->i_uid               = di->di_uid;
-        ei->i_gid               = di->di_gid;
+	ei->i_dtime = ei->i_links_count ? 0 : ip->i_mtime;
+	ei->i_size = ip->i_size;
+	ei->i_atime = ip->i_atime;
+	ei->i_mtime = ip->i_mtime;
+	ei->i_ctime = ip->i_ctime;
+	ei->i_flags = ip->i_flags;
+	ei->i_flags = 0;
+	ei->i_flags |= (ip->i_flags & APPEND) ? EXT2_APPEND_FL: 0;
+	ei->i_flags |= (ip->i_flags & IMMUTABLE) ? EXT2_IMMUTABLE_FL: 0;
+	ei->i_blocks = ip->i_blocks;
+	ei->i_generation = ip->i_gen;
+	ei->i_uid = ip->i_uid;
+	ei->i_gid = ip->i_gid;
 	/* XXX use memcpy */
-        for(i = 0; i < NDADDR; i++)
-                ei->i_block[i] = di->di_db[i];
-        for(i = 0; i < NIADDR; i++)
-                ei->i_block[EXT2_NDIR_BLOCKS + i] = di->di_ib[i];
+	for(i = 0; i < NDADDR; i++)
+		ei->i_block[i] = ip->i_db[i];
+	for(i = 0; i < NIADDR; i++)
+		ei->i_block[EXT2_NDIR_BLOCKS + i] = ip->i_ib[i];
 }
diff --git a/sys/gnu/ext2fs/ext2_linux_balloc.c b/sys/gnu/ext2fs/ext2_linux_balloc.c
index fc723114dfa6..632044009643 100644
--- a/sys/gnu/ext2fs/ext2_linux_balloc.c
+++ b/sys/gnu/ext2fs/ext2_linux_balloc.c
@@ -35,9 +35,8 @@
 #include <sys/mount.h>
 #include <sys/vnode.h>
 
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/ufsmount.h>
+#include <gnu/ext2fs/inode.h>
+#include <gnu/ext2fs/ext2_mount.h>
 #include <gnu/ext2fs/ext2_extern.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
@@ -61,13 +60,13 @@ static void read_block_bitmap (struct mount * mp,
 			       unsigned int block_group,
 			       unsigned long bitmap_nr)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	struct ext2_group_desc * gdp;
 	struct buffer_head * bh;
 	int    error;
 	
 	gdp = get_group_desc (mp, block_group, NULL);
-	if ((error = bread (VFSTOUFS(mp)->um_devvp, 
+	if ((error = bread (VFSTOEXT2(mp)->um_devvp,
 		fsbtodb(sb, gdp->bg_block_bitmap),sb->s_blocksize, NOCRED, &bh)) != 0)
 		panic ( "read_block_bitmap: "
 			    "Cannot read block bitmap - "
@@ -93,7 +92,7 @@ static int load__block_bitmap (struct mount * mp,
 			       unsigned int block_group)
 {
 	int i, j;
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	unsigned long block_bitmap_number;
 	struct buffer_head * block_bitmap;
 
@@ -152,7 +151,7 @@ static int load__block_bitmap (struct mount * mp,
 static __inline int load_block_bitmap (struct mount * mp,
 				       unsigned int block_group)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	if (sb->s_loaded_block_bitmaps > 0 &&
 	    sb->s_block_bitmap_number[0] == block_group)
 		return 0;
@@ -168,7 +167,7 @@ static __inline int load_block_bitmap (struct mount * mp,
 void ext2_free_blocks (struct mount * mp, unsigned long block,
 		       unsigned long count)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	struct buffer_head * bh;
 	struct buffer_head * bh2;
 	unsigned long block_group;
@@ -182,13 +181,13 @@ void ext2_free_blocks (struct mount * mp, unsigned long block,
 		printf ("ext2_free_blocks: nonexistent device");
 		return;
 	}
-	lock_super (VFSTOUFS(mp)->um_devvp);
+	lock_super (VFSTOEXT2(mp)->um_devvp);
 	if (block < es->s_first_data_block || 
 	    (block + count) > es->s_blocks_count) {
 		printf ( "ext2_free_blocks: "
 			    "Freeing blocks not in datazone - "
 			    "block = %lu, count = %lu", block, count);
-		unlock_super (VFSTOUFS(mp)->um_devvp);
+		unlock_super (VFSTOEXT2(mp)->um_devvp);
 		return;
 	}
 
@@ -238,7 +237,7 @@ void ext2_free_blocks (struct mount * mp, unsigned long block,
 	}
 ****/
 	sb->s_dirt = 1;
-	unlock_super (VFSTOUFS(mp)->um_devvp);
+	unlock_super (VFSTOEXT2(mp)->um_devvp);
 	return;
 }
 
@@ -253,7 +252,7 @@ int ext2_new_block (struct mount * mp, unsigned long goal,
 		    u_int32_t * prealloc_count,
 		    u_int32_t * prealloc_block)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	struct buffer_head * bh;
 	struct buffer_head * bh2;
 	char * p, * r;
@@ -269,7 +268,7 @@ int ext2_new_block (struct mount * mp, unsigned long goal,
 		printf ("ext2_new_block: nonexistent device");
 		return 0;
 	}
-	lock_super (VFSTOUFS(mp)->um_devvp);
+	lock_super (VFSTOEXT2(mp)->um_devvp);
 
         ext2_debug ("goal=%lu.\n", goal);
 
@@ -356,7 +355,7 @@ repeat:
 			break;
 	}
 	if (k >= sb->s_groups_count) {
-		unlock_super (VFSTOUFS(mp)->um_devvp);
+		unlock_super (VFSTOEXT2(mp)->um_devvp);
 		return 0;
 	}
 	bitmap_nr = load_block_bitmap (mp, i);
@@ -372,7 +371,7 @@ repeat:
 	if (j >= EXT2_BLOCKS_PER_GROUP(sb)) {
 		printf ( "ext2_new_block: "
 			 "Free blocks count corrupted for block group %d", i);
-		unlock_super (VFSTOUFS(mp)->um_devvp);
+		unlock_super (VFSTOEXT2(mp)->um_devvp);
 		return 0;
 	}
 
@@ -439,7 +438,7 @@ got_block:
 		printf ( "ext2_new_block: "
 			    "block >= blocks count - "
 			    "block_group = %d, block=%d", i, j);
-		unlock_super (VFSTOUFS(mp)->um_devvp);
+		unlock_super (VFSTOEXT2(mp)->um_devvp);
 		return 0;
 	}
 
@@ -450,14 +449,14 @@ got_block:
 	mark_buffer_dirty(bh2);
 	es->s_free_blocks_count--;
 	sb->s_dirt = 1;
-	unlock_super (VFSTOUFS(mp)->um_devvp);
+	unlock_super (VFSTOEXT2(mp)->um_devvp);
 	return j;
 }
 
 #ifdef unused
 static unsigned long ext2_count_free_blocks (struct mount * mp)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 #ifdef EXT2FS_DEBUG
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x;
@@ -465,7 +464,7 @@ static unsigned long ext2_count_free_blocks (struct mount * mp)
 	struct ext2_group_desc * gdp;
 	int i;
 	
-	lock_super (VFSTOUFS(mp)->um_devvp);
+	lock_super (VFSTOEXT2(mp)->um_devvp);
 	es = sb->s_es;
 	desc_count = 0;
 	bitmap_count = 0;
@@ -482,7 +481,7 @@ static unsigned long ext2_count_free_blocks (struct mount * mp)
 	}
 	ext2_debug( "stored = %lu, computed = %lu, %lu\n",
 	       es->s_free_blocks_count, desc_count, bitmap_count);
-	unlock_super (VFSTOUFS(mp)->um_devvp);
+	unlock_super (VFSTOEXT2(mp)->um_devvp);
 	return bitmap_count;
 #else
 	return sb->s_es->s_free_blocks_count;
@@ -520,7 +519,7 @@ int ext2_group_sparse(int group)
 #ifdef unused
 static void ext2_check_blocks_bitmap (struct mount * mp)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	struct buffer_head * bh;
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x;
@@ -529,7 +528,7 @@ static void ext2_check_blocks_bitmap (struct mount * mp)
 	struct ext2_group_desc * gdp;
 	int i, j;
 
-	lock_super (VFSTOUFS(mp)->um_devvp);
+	lock_super (VFSTOEXT2(mp)->um_devvp);
 	es = sb->s_es;
 	desc_count = 0;
 	bitmap_count = 0;
@@ -586,7 +585,7 @@ static void ext2_check_blocks_bitmap (struct mount * mp)
 			    "Wrong free blocks count in super block, "
 			    "stored = %lu, counted = %lu",
 			    (unsigned long) es->s_free_blocks_count, bitmap_count);
-	unlock_super (VFSTOUFS(mp)->um_devvp);
+	unlock_super (VFSTOEXT2(mp)->um_devvp);
 }
 #endif /* unused */
 
diff --git a/sys/gnu/ext2fs/ext2_linux_ialloc.c b/sys/gnu/ext2fs/ext2_linux_ialloc.c
index 01ae55b078dc..64d96b21104c 100644
--- a/sys/gnu/ext2fs/ext2_linux_ialloc.c
+++ b/sys/gnu/ext2fs/ext2_linux_ialloc.c
@@ -36,10 +36,8 @@
 #include <sys/mount.h>
 #include <sys/vnode.h>
 
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-#include <ufs/ufs/ufsmount.h>
+#include <gnu/ext2fs/inode.h>
+#include <gnu/ext2fs/ext2_mount.h>
 #include <gnu/ext2fs/ext2_extern.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
@@ -69,7 +67,7 @@ struct ext2_group_desc * get_group_desc (struct mount * mp,
 						unsigned int block_group,
 						struct buffer_head ** bh)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	unsigned long group_desc;
 	unsigned long desc;
 	struct ext2_group_desc * gdp;
@@ -98,13 +96,13 @@ static void read_inode_bitmap (struct mount * mp,
 			       unsigned long block_group,
 			       unsigned int bitmap_nr)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	struct ext2_group_desc * gdp;
 	struct buffer_head * bh;
 	int	error;
 
 	gdp = get_group_desc (mp, block_group, NULL);
-	if ((error = bread (VFSTOUFS(mp)->um_devvp, 
+	if ((error = bread (VFSTOEXT2(mp)->um_devvp,
 			    fsbtodb(sb, gdp->bg_inode_bitmap), 
 			    sb->s_blocksize,
 			    NOCRED, &bh)) != 0)
@@ -131,7 +129,7 @@ static void read_inode_bitmap (struct mount * mp,
 static int load_inode_bitmap (struct mount * mp,
 			      unsigned int block_group)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	int i, j;
 	unsigned long inode_bitmap_number;
 	struct buffer_head * inode_bitmap;
@@ -447,14 +445,14 @@ repeat:
 static unsigned long ext2_count_free_inodes (struct mount * mp)
 {
 #ifdef EXT2FS_DEBUG
-        struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+        struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x;
 	int bitmap_nr;
 	struct ext2_group_desc * gdp;
 	int i;
 
-	lock_super (VFSTOUFS(mp)->um_devvp);
+	lock_super (VFSTOEXT2(mp)->um_devvp);
 	es = sb->s_es;
 	desc_count = 0;
 	bitmap_count = 0;
@@ -471,10 +469,10 @@ static unsigned long ext2_count_free_inodes (struct mount * mp)
 	}
 	ext2_debug("stored = %lu, computed = %lu, %lu\n",
 		es->s_free_inodes_count, desc_count, bitmap_count);
-	unlock_super (VFSTOUFS(mp)->um_devvp);
+	unlock_super (VFSTOEXT2(mp)->um_devvp);
 	return desc_count;
 #else
-	return VFSTOUFS(mp)->um_e2fsb->s_free_inodes_count;
+	return VFSTOEXT2(mp)->um_e2fsb->s_free_inodes_count;
 #endif
 }
 #endif /* unused */
diff --git a/sys/gnu/ext2fs/ext2_lookup.c b/sys/gnu/ext2fs/ext2_lookup.c
index 2c1de41414f4..14b78b58a7cf 100644
--- a/sys/gnu/ext2fs/ext2_lookup.c
+++ b/sys/gnu/ext2fs/ext2_lookup.c
@@ -55,13 +55,10 @@
 #include <sys/malloc.h>
 #include <sys/dirent.h>
 
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
 #include <ufs/ufs/dir.h>
-#include <ufs/ufs/ufsmount.h>
-#include <ufs/ufs/ufs_extern.h>
 
+#include <gnu/ext2fs/inode.h>
+#include <gnu/ext2fs/ext2_mount.h>
 #include <gnu/ext2fs/ext2_extern.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
@@ -364,7 +361,7 @@ ext2_lookup(ap)
 	 * profiling time and hence has been removed in the interest
 	 * of simplicity.
 	 */
-	bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
+	bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
 	if (nameiop != LOOKUP || dp->i_diroff == 0 ||
 	    dp->i_diroff > dp->i_size) {
 		entryoffsetinblock = 0;
@@ -373,7 +370,8 @@ ext2_lookup(ap)
 	} else {
 		dp->i_offset = dp->i_diroff;
 		if ((entryoffsetinblock = dp->i_offset & bmask) &&
-		    (error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)))
+		    (error = ext2_blkatoff(vdp, (off_t)dp->i_offset, NULL,
+		    &bp)))
 			return (error);
 		numdirpasses = 2;
 		nchstats.ncs_2passes++;
@@ -391,7 +389,8 @@ searchloop:
 			if (bp != NULL)
 				brelse(bp);
 			if ((error =
-			    UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)) != 0)
+			    ext2_blkatoff(vdp, (off_t)dp->i_offset, NULL,
+			    &bp)) != 0)
 				return (error);
 			entryoffsetinblock = 0;
 		}
@@ -416,7 +415,7 @@ searchloop:
 		if (ep->rec_len == 0 ||
 		    (dirchk && ext2_dirbadentry(vdp, ep, entryoffsetinblock))) {
 			int i;
-			ufs_dirbad(dp, dp->i_offset, "mangled entry");
+			ext2_dirbad(dp, dp->i_offset, "mangled entry");
 			i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
 			dp->i_offset += i;
 			entryoffsetinblock += i;
@@ -558,7 +557,7 @@ found:
 	 */
 	if (entryoffsetinblock + EXT2_DIR_REC_LEN(ep->name_len)
 		> dp->i_size) {
-		ufs_dirbad(dp, dp->i_offset, "i_size too small");
+		ext2_dirbad(dp, dp->i_offset, "i_size too small");
 		dp->i_size = entryoffsetinblock+EXT2_DIR_REC_LEN(ep->name_len);
 		dp->i_flag |= IN_CHANGE | IN_UPDATE;
 	}
@@ -700,6 +699,21 @@ found:
 	return (0);
 }
 
+void
+ext2_dirbad(ip, offset, how)
+	struct inode *ip;
+	doff_t offset;
+	char *how;
+{
+	struct mount *mp;
+
+	mp = ITOV(ip)->v_mount;
+	(void)printf("%s: bad dir ino %lu at offset %ld: %s\n",
+	    mp->mnt_stat.f_mntonname, (u_long)ip->i_number, (long)offset, how);
+	if ((mp->mnt_flag & MNT_RDONLY) == 0)
+		panic("ext2_dirbad: bad dir");
+}
+
 /*
  * Do consistency checking on a directory entry:
  *	record length must be multiple of 4
@@ -804,7 +818,7 @@ ext2_direnter(ip, dvp, cnp)
 		auio.uio_td = (struct thread *)0;
 		error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
 		if (DIRBLKSIZ >
-		    VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
+		    VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
 			/* XXX should grow with balloc() */
 			panic("ext2_direnter: frag size");
 		else if (!error) {
@@ -835,7 +849,8 @@ ext2_direnter(ip, dvp, cnp)
 	/*
 	 * Get the block containing the space for the new directory entry.
 	 */
-	if ((error = UFS_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp)) != 0)
+	if ((error = ext2_blkatoff(dvp, (off_t)dp->i_offset, &dirbuf,
+	    &bp)) != 0)
 		return (error);
 	/*
 	 * Find space for the new entry. In the simple case, the entry at
@@ -881,7 +896,7 @@ ext2_direnter(ip, dvp, cnp)
 	error = BUF_WRITE(bp);
 	dp->i_flag |= IN_CHANGE | IN_UPDATE;
 	if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
-		error = UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC,
+		error = ext2_truncate(dvp, (off_t)dp->i_endoff, IO_SYNC,
 		    cnp->cn_cred, cnp->cn_thread);
 	return (error);
 }
@@ -914,7 +929,8 @@ ext2_dirremove(dvp, cnp)
 		 * First entry in block: set d_ino to zero.
 		 */
 		if ((error =
-		    UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
+		    ext2_blkatoff(dvp, (off_t)dp->i_offset, (char **)&ep,
+		    &bp)) != 0)
 			return (error);
 		ep->inode = 0;
 		error = BUF_WRITE(bp);
@@ -924,7 +940,7 @@ ext2_dirremove(dvp, cnp)
 	/*
 	 * Collapse new free space into previous entry.
 	 */
-	if ((error = UFS_BLKATOFF(dvp, (off_t)(dp->i_offset - dp->i_count),
+	if ((error = ext2_blkatoff(dvp, (off_t)(dp->i_offset - dp->i_count),
 	    (char **)&ep, &bp)) != 0)
 		return (error);
 	ep->rec_len += dp->i_reclen;
@@ -948,7 +964,8 @@ ext2_dirrewrite(dp, ip, cnp)
 	struct vnode *vdp = ITOV(dp);
 	int error;
 
-	if ((error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
+	if ((error = ext2_blkatoff(vdp, (off_t)dp->i_offset, (char **)&ep,
+	    &bp)) != 0)
 		return (error);
 	ep->inode = ip->i_number;
 	if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
diff --git a/sys/gnu/ext2fs/ext2_readwrite.c b/sys/gnu/ext2fs/ext2_readwrite.c
index 2772f7b2306e..73f900cd3230 100644
--- a/sys/gnu/ext2fs/ext2_readwrite.c
+++ b/sys/gnu/ext2fs/ext2_readwrite.c
@@ -301,12 +301,12 @@ WRITE(ap)
 		ip->i_mode &= ~(ISUID | ISGID);
 	if (error) {
 		if (ioflag & IO_UNIT) {
-			(void)UFS_TRUNCATE(vp, osize,
+			(void)ext2_truncate(vp, osize,
 			    ioflag & IO_SYNC, ap->a_cred, uio->uio_td);
 			uio->uio_offset -= resid - uio->uio_resid;
 			uio->uio_resid = resid;
 		}
 	} else if (resid > uio->uio_resid && (ioflag & IO_SYNC))
-		error = UFS_UPDATE(vp, 1);
+		error = ext2_update(vp, 1);
 	return (error);
 }
diff --git a/sys/gnu/ext2fs/ext2_subr.c b/sys/gnu/ext2fs/ext2_subr.c
index 69eecf1e236b..587ed0520f6d 100644
--- a/sys/gnu/ext2fs/ext2_subr.c
+++ b/sys/gnu/ext2fs/ext2_subr.c
@@ -50,9 +50,7 @@
 #include <sys/ucred.h>
 #include <sys/vnode.h>
 
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-
+#include <gnu/ext2fs/inode.h>
 #include <gnu/ext2fs/ext2_extern.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
 #include <gnu/ext2fs/fs.h>
@@ -121,7 +119,7 @@ ext2_checkoverlap(bp, ip)
 			continue;
 		vprint("Disk overlap", vp);
 		(void)printf("\tstart %d, end %d overlap start %lld, end %ld\n",
-			start, last, ep->b_blkno,
+			start, last, (long long)ep->b_blkno,
 			(long)(ep->b_blkno + btodb(ep->b_bcount) - 1));
 		panic("Disk buffer overlap");
 	}
diff --git a/sys/gnu/ext2fs/ext2_vfsops.c b/sys/gnu/ext2fs/ext2_vfsops.c
index 54c43058cb3d..b9afe91a1f7f 100644
--- a/sys/gnu/ext2fs/ext2_vfsops.c
+++ b/sys/gnu/ext2fs/ext2_vfsops.c
@@ -40,8 +40,6 @@
  * $FreeBSD$
  */
 
-#include "opt_quota.h"
-
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/namei.h>
@@ -57,12 +55,8 @@
 #include <sys/stat.h>
 #include <sys/mutex.h>
 
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/ufsmount.h>
-#include <ufs/ufs/inode.h>
-#include <ufs/ufs/ufs_extern.h>
-
+#include <gnu/ext2fs/ext2_mount.h>
+#include <gnu/ext2fs/inode.h>
 
 #include <gnu/ext2fs/fs.h>
 #include <gnu/ext2fs/ext2_extern.h>
@@ -71,26 +65,29 @@
 
 static int ext2_fhtovp(struct mount *, struct fid *, struct vnode **);
 static int ext2_flushfiles(struct mount *mp, int flags, struct thread *td);
+static int ext2_init(struct vfsconf *);
 static int ext2_mount(struct mount *,
 	    char *, caddr_t, struct nameidata *, struct thread *);
 static int ext2_mountfs(struct vnode *, struct mount *, struct thread *);
 static int ext2_reload(struct mount *mountp, struct ucred *cred,
 			struct thread *td);
-static int ext2_sbupdate(struct ufsmount *, int);
+static int ext2_root(struct mount *, struct vnode **vpp);
+static int ext2_sbupdate(struct ext2mount *, int);
 static int ext2_statfs(struct mount *, struct statfs *, struct thread *);
 static int ext2_sync(struct mount *, int, struct ucred *, struct thread *);
 static int ext2_unmount(struct mount *, int, struct thread *);
 static int ext2_vget(struct mount *, ino_t, int, struct vnode **);
 static int ext2_vptofh(struct vnode *, struct fid *);
 
-static MALLOC_DEFINE(M_EXT2NODE, "EXT2 node", "EXT2 vnode private part");
+MALLOC_DEFINE(M_EXT2NODE, "EXT2 node", "EXT2 vnode private part");
+static MALLOC_DEFINE(M_EXT2MNT, "EXT2 mount", "EXT2 mount structure");
 
 static struct vfsops ext2fs_vfsops = {
 	ext2_mount,
-	ufs_start,		/* empty function */
+	vfs_stdstart,
 	ext2_unmount,
-	ufs_root,		/* root inode via vget */
-	ufs_quotactl,		/* does operations associated with quotas */
+	ext2_root,		/* root inode via vget */
+	vfs_stdquotactl,
 	ext2_statfs,
 	ext2_sync,
 	ext2_vget,
@@ -129,7 +126,7 @@ ext2_mountroot()
 	register struct ext2_sb_info *fs;
 	register struct mount *mp;
 	struct thread *td = curthread;
-	struct ufsmount *ump;
+	struct ext2mount *ump;
 	u_int size;
 	int error;
 	
@@ -155,7 +152,7 @@ ext2_mountroot()
 	TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list);
 	mp->mnt_flag |= MNT_ROOTFS;
 	mp->mnt_vnodecovered = NULLVP;
-	ump = VFSTOUFS(mp);
+	ump = VFSTOEXT2(mp);
 	fs = ump->um_e2fs;
 	bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
 	fs->fs_fsmnt[0] = '/';
@@ -180,13 +177,13 @@ static int
 ext2_mount(mp, path, data, ndp, td)
 	register struct mount *mp;	
 	char *path;
-	caddr_t data;		/* this is actually a (struct ufs_args *) */
+	caddr_t data;		/* this is actually a (struct ext2_args *) */
 	struct nameidata *ndp;
 	struct thread *td;
 {
 	struct vnode *devvp;
-	struct ufs_args args;
-	struct ufsmount *ump = 0;
+	struct ext2_args args;
+	struct ext2mount *ump = 0;
 	register struct ext2_sb_info *fs;
 	size_t size;
 	int error, flags;
@@ -195,7 +192,7 @@ ext2_mount(mp, path, data, ndp, td)
 	/* Double-check the length of path.. */
 	if (strlen(path) >= MAXMNTLEN - 1)
 		return (ENAMETOOLONG);
-	error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args));
+	error = copyin(data, (caddr_t)&args, sizeof (struct ext2_args));
 	if (error != 0)
 		return (error);
 	/*
@@ -203,7 +200,7 @@ ext2_mount(mp, path, data, ndp, td)
 	 * read/write; if there is no device name, that's all we do.
 	 */
 	if (mp->mnt_flag & MNT_UPDATE) {
-		ump = VFSTOUFS(mp);
+		ump = VFSTOEXT2(mp);
 		fs = ump->um_e2fs;
 		error = 0;
 		if (fs->s_rd_only == 0 && (mp->mnt_flag & MNT_RDONLY)) {
@@ -310,7 +307,7 @@ ext2_mount(mp, path, data, ndp, td)
 		vrele(devvp);
 		return (error);
 	}
-	ump = VFSTOUFS(mp);
+	ump = VFSTOEXT2(mp);
 	fs = ump->um_e2fs;
 	/*
 	 * Note that this strncpy() is ok because of a check at the start
@@ -466,7 +463,7 @@ static int compute_sb_data(devvp, es, fs)
     V(s_db_per_group)
 
     fs->s_group_desc = bsd_malloc(db_count * sizeof (struct buf *),
-		M_UFSMNT, M_WAITOK);
+		M_EXT2MNT, M_WAITOK);
 
     /* adjust logic_sb_block */
     if(fs->s_blocksize > SBSIZE) 
@@ -481,7 +478,7 @@ static int compute_sb_data(devvp, es, fs)
 	if(error) {
 	    for (j = 0; j < i; j++)
 		brelse(fs->s_group_desc[j]);
-	    bsd_free(fs->s_group_desc, M_UFSMNT);
+	    bsd_free(fs->s_group_desc, M_EXT2MNT);
 	    printf("EXT2-fs: unable to read group descriptors (%d)\n", error);
 	    return EIO;
 	}
@@ -491,7 +488,7 @@ static int compute_sb_data(devvp, es, fs)
     if(!ext2_check_descriptors(fs)) {
 	    for (j = 0; j < db_count; j++)
 		    ULCK_BUF(fs->s_group_desc[j])
-	    bsd_free(fs->s_group_desc, M_UFSMNT);
+	    bsd_free(fs->s_group_desc, M_EXT2MNT);
 	    printf("EXT2-fs: (ext2_check_descriptors failure) "
 		   "unable to read group descriptors\n");
 	    return EIO;
@@ -539,7 +536,7 @@ ext2_reload(mountp, cred, td)
 	/*
 	 * Step 1: invalidate all cached meta-data.
 	 */
-	devvp = VFSTOUFS(mountp)->um_devvp;
+	devvp = VFSTOEXT2(mountp)->um_devvp;
 	if (vinvalbuf(devvp, 0, cred, td, 0, 0))
 		panic("ext2_reload: dirty1");
 	/*
@@ -553,7 +550,7 @@ ext2_reload(mountp, cred, td)
 		brelse(bp);
 		return (EIO);		/* XXX needs translation */
 	}
-	fs = VFSTOUFS(mountp)->um_e2fs;
+	fs = VFSTOEXT2(mountp)->um_e2fs;
 	bcopy(bp->b_data, fs->s_es, sizeof(struct ext2_super_block));
 
 	if((error = compute_sb_data(devvp, es, fs)) != 0) {
@@ -600,9 +597,8 @@ loop:
 			vput(vp);
 			return (error);
 		}
-		ext2_ei2di((struct ext2_inode *) ((char *)bp->b_data + 
-		    EXT2_INODE_SIZE * ino_to_fsbo(fs, ip->i_number)), 
-		    &ip->i_din);
+		ext2_ei2i((struct ext2_inode *) ((char *)bp->b_data +
+		    EXT2_INODE_SIZE * ino_to_fsbo(fs, ip->i_number)), ip);
 		brelse(bp);
 		vput(vp);
 		mtx_lock(&mntvnode_mtx);
@@ -620,12 +616,12 @@ ext2_mountfs(devvp, mp, td)
 	struct mount *mp;
 	struct thread *td;
 {
-	register struct ufsmount *ump;
+	register struct ext2mount *ump;
 	struct buf *bp;
 	register struct ext2_sb_info *fs;
 	struct ext2_super_block * es;
 	dev_t dev = devvp->v_rdev;
-	int error, i;
+	int error;
 	int ronly;
 
 	/*
@@ -677,22 +673,16 @@ ext2_mountfs(devvp, mp, td)
 			goto out;
 		}
 	}
-	ump = bsd_malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
+	ump = bsd_malloc(sizeof *ump, M_EXT2MNT, M_WAITOK);
 	bzero((caddr_t)ump, sizeof *ump);
-	ump->um_malloctype = M_EXT2NODE;
-	ump->um_blkatoff = ext2_blkatoff;
-	ump->um_truncate = ext2_truncate;
-	ump->um_update = ext2_update;
-	ump->um_valloc = ext2_valloc;
-	ump->um_vfree = ext2_vfree;
 	/* I don't know whether this is the right strategy. Note that
 	   we dynamically allocate both a ext2_sb_info and a ext2_super_block
 	   while Linux keeps the super block in a locked buffer
 	 */
 	ump->um_e2fs = bsd_malloc(sizeof(struct ext2_sb_info), 
-		M_UFSMNT, M_WAITOK);
+		M_EXT2MNT, M_WAITOK);
 	ump->um_e2fs->s_es = bsd_malloc(sizeof(struct ext2_super_block), 
-		M_UFSMNT, M_WAITOK);
+		M_EXT2MNT, M_WAITOK);
 	bcopy(es, ump->um_e2fs->s_es, (u_int)sizeof(struct ext2_super_block));
 	if ((error = compute_sb_data(devvp, ump->um_e2fs->s_es, ump->um_e2fs)))
 		goto out;
@@ -720,14 +710,12 @@ ext2_mountfs(devvp, mp, td)
 	ump->um_mountp = mp;
 	ump->um_dev = dev;
 	ump->um_devvp = devvp;
-	/* setting those two parameters allows us to use 
+	/* setting those two parameters allowed us to use
 	   ufs_bmap w/o changse !
 	*/
 	ump->um_nindir = EXT2_ADDR_PER_BLOCK(fs);
 	ump->um_bptrtodb = fs->s_es->s_log_block_size + 1;
 	ump->um_seqinc = EXT2_FRAGS_PER_BLOCK(fs);
-	for (i = 0; i < MAXQUOTAS; i++)
-		ump->um_quotas[i] = NULLVP; 
 	devvp->v_rdev->si_mountpoint = mp;
 	if (ronly == 0) 
 		ext2_sbupdate(ump, MNT_WAIT);
@@ -737,9 +725,9 @@ out:
 		brelse(bp);
 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, td);
 	if (ump) {
-		bsd_free(ump->um_e2fs->s_es, M_UFSMNT);
-		bsd_free(ump->um_e2fs, M_UFSMNT);
-		bsd_free(ump, M_UFSMNT);
+		bsd_free(ump->um_e2fs->s_es, M_EXT2MNT);
+		bsd_free(ump->um_e2fs, M_EXT2MNT);
+		bsd_free(ump, M_EXT2MNT);
 		mp->mnt_data = (qaddr_t)0;
 	}
 	return (error);
@@ -754,7 +742,7 @@ ext2_unmount(mp, mntflags, td)
 	int mntflags;
 	struct thread *td;
 {
-	register struct ufsmount *ump;
+	register struct ext2mount *ump;
 	register struct ext2_sb_info *fs;
 	int error, flags, ronly, i;
 
@@ -766,7 +754,7 @@ ext2_unmount(mp, mntflags, td)
 	}
 	if ((error = ext2_flushfiles(mp, flags, td)) != 0)
 		return (error);
-	ump = VFSTOUFS(mp);
+	ump = VFSTOEXT2(mp);
 	fs = ump->um_e2fs;
 	ronly = fs->s_rd_only;
 	if (ronly == 0) {
@@ -778,7 +766,7 @@ ext2_unmount(mp, mntflags, td)
 	/* release buffers containing group descriptors */
 	for(i = 0; i < fs->s_db_per_group; i++) 
 		ULCK_BUF(fs->s_group_desc[i])
-	bsd_free(fs->s_group_desc, M_UFSMNT);
+	bsd_free(fs->s_group_desc, M_EXT2MNT);
 
 	/* release cached inode/block bitmaps */
         for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
@@ -793,9 +781,9 @@ ext2_unmount(mp, mntflags, td)
 	error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE,
 		NOCRED, td);
 	vrele(ump->um_devvp);
-	bsd_free(fs->s_es, M_UFSMNT);
-	bsd_free(fs, M_UFSMNT);
-	bsd_free(ump, M_UFSMNT);
+	bsd_free(fs->s_es, M_EXT2MNT);
+	bsd_free(fs, M_EXT2MNT);
+	bsd_free(ump, M_EXT2MNT);
 	mp->mnt_data = (qaddr_t)0;
 	mp->mnt_flag &= ~MNT_LOCAL;
 	return (error);
@@ -810,28 +798,8 @@ ext2_flushfiles(mp, flags, td)
 	int flags;
 	struct thread *td;
 {
-	register struct ufsmount *ump;
 	int error;
-#if QUOTA
-	int i;
-#endif
 
-	ump = VFSTOUFS(mp);
-#if QUOTA
-	if (mp->mnt_flag & MNT_QUOTA) {
-		if ((error = vflush(mp, 0, SKIPSYSTEM|flags)) != 0)
-			return (error);
-		for (i = 0; i < MAXQUOTAS; i++) {
-			if (ump->um_quotas[i] == NULLVP)
-				continue;
-			quotaoff(td, mp, i);
-		}
-		/*
-		 * Here we fall through to vflush again to ensure
-		 * that we have gotten rid of all the system vnodes.
-		 */
-	}
-#endif
 	error = vflush(mp, 0, flags);
 	return (error);
 }
@@ -847,12 +815,12 @@ ext2_statfs(mp, sbp, td)
 	struct thread *td;
 {
         unsigned long overhead;
-	register struct ufsmount *ump;
+	register struct ext2mount *ump;
 	register struct ext2_sb_info *fs;
 	register struct ext2_super_block *es;
 	int i, nsb;
 
-	ump = VFSTOUFS(mp);
+	ump = VFSTOEXT2(mp);
 	fs = ump->um_e2fs;
 	es = fs->s_es;
 
@@ -908,7 +876,7 @@ ext2_sync(mp, waitfor, cred, td)
 {
 	struct vnode *nvp, *vp;
 	struct inode *ip;
-	struct ufsmount *ump = VFSTOUFS(mp);
+	struct ext2mount *ump = VFSTOEXT2(mp);
 	struct ext2_sb_info *fs;
 	int error, allerror = 0;
 
@@ -964,9 +932,6 @@ loop:
 			allerror = error;
 		VOP_UNLOCK(ump->um_devvp, 0, td);
 	}
-#if QUOTA
-	qsync(mp);
-#endif
 	/*
 	 * Write back modified superblock.
 	 */
@@ -994,17 +959,17 @@ ext2_vget(mp, ino, flags, vpp)
 {
 	register struct ext2_sb_info *fs;
 	register struct inode *ip;
-	struct ufsmount *ump;
+	struct ext2mount *ump;
 	struct buf *bp;
 	struct vnode *vp;
 	dev_t dev;
 	int i, error;
 	int used_blocks;
 
-	ump = VFSTOUFS(mp);
+	ump = VFSTOEXT2(mp);
 	dev = ump->um_dev;
 restart:
-	if ((error = ufs_ihashget(dev, ino, flags, vpp)) != 0)
+	if ((error = ext2_ihashget(dev, ino, flags, vpp)) != 0)
 		return (error);
 	if (*vpp != NULL)
 		return (0);
@@ -1048,17 +1013,13 @@ restart:
 	ip->i_e2fs = fs = ump->um_e2fs;
 	ip->i_dev = dev;
 	ip->i_number = ino;
-#if QUOTA
-	for (i = 0; i < MAXQUOTAS; i++)
-		ip->i_dquot[i] = NODQUOT;
-#endif
 	/*
 	 * Put it onto its hash chain and lock it so that other requests for
 	 * this inode will block if they arrive while we are sleeping waiting
 	 * for old data structures to be purged or for the contents of the
 	 * disk portion of this inode to be read.
 	 */
-	ufs_ihashins(ip);
+	ext2_ihashins(ip);
 
 	if (ext2fs_inode_hash_lock < 0)
 		wakeup(&ext2fs_inode_hash_lock);
@@ -1082,8 +1043,8 @@ printf("ext2_vget(%d) dbn= %d ", ino, fsbtodb(fs, ino_to_fsba(fs, ino)));
 		return (error);
 	}
 	/* convert ext2 inode to dinode */
-	ext2_ei2di((struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE *
-			ino_to_fsbo(fs, ino)), &ip->i_din);
+	ext2_ei2i((struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE *
+			ino_to_fsbo(fs, ino)), ip);
 	ip->i_block_group = ino_to_cg(fs, ino);
 	ip->i_next_alloc_block = 0;
 	ip->i_next_alloc_goal = 0;
@@ -1107,7 +1068,7 @@ printf("ext2_vget(%d) dbn= %d ", ino, fsbtodb(fs, ino_to_fsba(fs, ino)));
 	 * Initialize the vnode from the inode, check for aliases.
 	 * Note that the underlying vnode may have changed.
 	 */
-	if ((error = ufs_vinit(mp, ext2_specop_p, ext2_fifoop_p, &vp)) != 0) {
+	if ((error = ext2_vinit(mp, ext2_specop_p, ext2_fifoop_p, &vp)) != 0) {
 		vput(vp);
 		*vpp = NULL;
 		return (error);
@@ -1146,15 +1107,32 @@ ext2_fhtovp(mp, fhp, vpp)
 	struct fid *fhp;
 	struct vnode **vpp;
 {
+	struct inode *ip;
 	register struct ufid *ufhp;
+	struct vnode *nvp;
 	struct ext2_sb_info *fs;
+	int error;
 
 	ufhp = (struct ufid *)fhp;
-	fs = VFSTOUFS(mp)->um_e2fs;
+	fs = VFSTOEXT2(mp)->um_e2fs;
 	if (ufhp->ufid_ino < ROOTINO ||
 	    ufhp->ufid_ino >= fs->s_groups_count * fs->s_es->s_inodes_per_group)
 		return (ESTALE);
-	return (ufs_fhtovp(mp, ufhp, vpp));
+
+	error = VFS_VGET(mp, ufhp->ufid_ino, LK_EXCLUSIVE, &nvp);
+	if (error) {
+		*vpp = NULLVP;
+		return (error);
+	}
+	ip = VTOI(nvp);
+	if (ip->i_mode == 0 ||
+	    ip->i_gen != ufhp->ufid_gen || ip->i_nlink <= 0) {
+		vput(nvp);
+		*vpp = NULLVP;
+		return (ESTALE);
+	}
+	*vpp = nvp;
+	return (0);
 }
 
 /*
@@ -1182,7 +1160,7 @@ ext2_vptofh(vp, fhp)
  */
 static int
 ext2_sbupdate(mp, waitfor)
-	struct ufsmount *mp;
+	struct ext2mount *mp;
 	int waitfor;
 {
 	register struct ext2_sb_info *fs = mp->um_e2fs;
@@ -1207,3 +1185,34 @@ printf("\nupdating superblock, waitfor=%s\n", waitfor == MNT_WAIT ? "yes":"no");
 
 	return (error);
 }
+
+/*
+ * Return the root of a filesystem.
+ */
+static int
+ext2_root(mp, vpp)
+	struct mount *mp;
+	struct vnode **vpp;
+{
+	struct vnode *nvp;
+	int error;
+
+	error = VFS_VGET(mp, (ino_t)ROOTINO, LK_EXCLUSIVE, &nvp);
+	if (error)
+		return (error);
+	*vpp = nvp;
+	return (0);
+}
+
+static int
+ext2_init(struct vfsconf *vfsp)
+{
+	static int done;
+
+	if (done)
+		return (0);
+	done = 1;
+	ext2_ihashinit();
+
+	return (0);
+}
diff --git a/sys/gnu/ext2fs/ext2_vnops.c b/sys/gnu/ext2fs/ext2_vnops.c
index 180ac3db063a..ba7b714cdaf9 100644
--- a/sys/gnu/ext2fs/ext2_vnops.c
+++ b/sys/gnu/ext2fs/ext2_vnops.c
@@ -46,34 +46,38 @@
  * $FreeBSD$
  */
 
-#include "opt_quota.h"
 #include "opt_suiddir.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/resourcevar.h>
 #include <sys/kernel.h>
+#include <sys/fcntl.h>
 #include <sys/stat.h>
 #include <sys/bio.h>
 #include <sys/buf.h>
 #include <sys/proc.h>
 #include <sys/mount.h>
+#include <sys/unistd.h>
 #include <sys/time.h>
 #include <sys/vnode.h>
 #include <sys/namei.h>
+#include <sys/lockf.h>
+#include <sys/event.h>
+#include <sys/conf.h>
+#include <sys/file.h>
 
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 #include <vm/vnode_pager.h>
 
+#include <fs/fifofs/fifo.h>
+
 #include <sys/signalvar.h>
 #include <ufs/ufs/dir.h>
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-#include <ufs/ufs/ufsmount.h>
-#include <ufs/ufs/ufs_extern.h>
 
+#include <gnu/ext2fs/inode.h>
+#include <gnu/ext2fs/ext2_mount.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
 #include <gnu/ext2fs/fs.h>
 #include <gnu/ext2fs/ext2_extern.h>
@@ -81,38 +85,81 @@
 
 static int ext2_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *);
 
-static int ext2_fsync(struct vop_fsync_args *);
-static int ext2_read(struct vop_read_args *);
-static int ext2_write(struct vop_write_args *);
-static int ext2_remove(struct vop_remove_args *);
-static int ext2_link(struct vop_link_args *);
-static int ext2_rename(struct vop_rename_args *);
-static int ext2_mkdir(struct vop_mkdir_args *);
-static int ext2_rmdir(struct vop_rmdir_args *);
+static int ext2_access(struct vop_access_args *);
+static int ext2_advlock(struct vop_advlock_args *);
+static int ext2_chmod(struct vnode *, int, struct ucred *, struct thread *);
+static int ext2_chown(struct vnode *, uid_t, gid_t, struct ucred *,
+    struct thread *);
+static int ext2_close(struct vop_close_args *);
 static int ext2_create(struct vop_create_args *);
+static int ext2_fsync(struct vop_fsync_args *);
+static int ext2_getattr(struct vop_getattr_args *);
+static int ext2_kqfilter(struct vop_kqfilter_args *ap);
+static int ext2_link(struct vop_link_args *);
+static int ext2_mkdir(struct vop_mkdir_args *);
 static int ext2_mknod(struct vop_mknod_args *);
+static int ext2_open(struct vop_open_args *);
+static int ext2_pathconf(struct vop_pathconf_args *);
+static int ext2_print(struct vop_print_args *);
+static int ext2_read(struct vop_read_args *);
+static int ext2_readlink(struct vop_readlink_args *);
+static int ext2_remove(struct vop_remove_args *);
+static int ext2_rename(struct vop_rename_args *);
+static int ext2_rmdir(struct vop_rmdir_args *);
+static int ext2_setattr(struct vop_setattr_args *);
+static int ext2_strategy(struct vop_strategy_args *);
 static int ext2_symlink(struct vop_symlink_args *);
+static int ext2_write(struct vop_write_args *);
+static int ext2fifo_close(struct vop_close_args *);
+static int ext2fifo_kqfilter(struct vop_kqfilter_args *);
+static int ext2fifo_read(struct vop_read_args *);
+static int ext2fifo_write(struct vop_write_args *);
+static int ext2spec_close(struct vop_close_args *);
+static int ext2spec_read(struct vop_read_args *);
+static int ext2spec_write(struct vop_write_args *);
+static int filt_ext2read(struct knote *kn, long hint);
+static int filt_ext2write(struct knote *kn, long hint);
+static int filt_ext2vnode(struct knote *kn, long hint);
+static void filt_ext2detach(struct knote *kn);
 
-/* Global vfs data structures for ufs. */
+/* Global vfs data structures for ext2. */
 vop_t **ext2_vnodeop_p;
 static struct vnodeopv_entry_desc ext2_vnodeop_entries[] = {
-	{ &vop_default_desc,		(vop_t *) ufs_vnoperate },
+	{ &vop_default_desc,		(vop_t *) vop_defaultop },
+	{ &vop_access_desc,		(vop_t *) ext2_access },
+	{ &vop_advlock_desc,		(vop_t *) ext2_advlock },
+	{ &vop_bmap_desc,		(vop_t *) ext2_bmap },
 	{ &vop_cachedlookup_desc,	(vop_t *) ext2_lookup },
+	{ &vop_close_desc,		(vop_t *) ext2_close },
+	{ &vop_create_desc,		(vop_t *) ext2_create },
 	{ &vop_fsync_desc,		(vop_t *) ext2_fsync },
+	{ &vop_getattr_desc,		(vop_t *) ext2_getattr },
+	{ &vop_getwritemount_desc,	(vop_t *) vop_stdgetwritemount },
 	{ &vop_inactive_desc,		(vop_t *) ext2_inactive },
+	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
+	{ &vop_link_desc,		(vop_t *) ext2_link },
+	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
 	{ &vop_lookup_desc,		(vop_t *) vfs_cache_lookup },
+	{ &vop_mkdir_desc,		(vop_t *) ext2_mkdir },
+	{ &vop_mknod_desc,		(vop_t *) ext2_mknod },
+	{ &vop_open_desc,		(vop_t *) ext2_open },
+	{ &vop_pathconf_desc,		(vop_t *) ext2_pathconf },
+	{ &vop_poll_desc,		(vop_t *) vop_stdpoll },
+	{ &vop_kqfilter_desc,		(vop_t *) ext2_kqfilter },
+	{ &vop_print_desc,		(vop_t *) ext2_print },
 	{ &vop_read_desc,		(vop_t *) ext2_read },
 	{ &vop_readdir_desc,		(vop_t *) ext2_readdir },
+	{ &vop_readlink_desc,		(vop_t *) ext2_readlink },
 	{ &vop_reallocblks_desc,	(vop_t *) ext2_reallocblks },
-	{ &vop_write_desc,		(vop_t *) ext2_write },
+	{ &vop_reclaim_desc,		(vop_t *) ext2_reclaim },
 	{ &vop_remove_desc,		(vop_t *) ext2_remove },
-	{ &vop_link_desc,		(vop_t *) ext2_link },
 	{ &vop_rename_desc,		(vop_t *) ext2_rename },
-	{ &vop_mkdir_desc,		(vop_t *) ext2_mkdir },
 	{ &vop_rmdir_desc,		(vop_t *) ext2_rmdir },
-	{ &vop_create_desc,		(vop_t *) ext2_create },
-	{ &vop_mknod_desc,		(vop_t *) ext2_mknod },
+	{ &vop_setattr_desc,		(vop_t *) ext2_setattr },
+	{ &vop_strategy_desc,		(vop_t *) ext2_strategy },
 	{ &vop_symlink_desc,		(vop_t *) ext2_symlink },
+	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
+	{ &vop_write_desc,		(vop_t *) ext2_write },
 	{ NULL, NULL }
 };
 static struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
@@ -120,9 +167,20 @@ static struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
 
 vop_t **ext2_specop_p;
 static struct vnodeopv_entry_desc ext2_specop_entries[] = {
-	{ &vop_default_desc,		(vop_t *) ufs_vnoperatespec },
+	{ &vop_default_desc,		(vop_t *) spec_vnoperate },
+	{ &vop_access_desc,		(vop_t *) ext2_access },
+	{ &vop_close_desc,		(vop_t *) ext2spec_close },
 	{ &vop_fsync_desc,		(vop_t *) ext2_fsync },
+	{ &vop_getattr_desc,		(vop_t *) ext2_getattr },
 	{ &vop_inactive_desc,		(vop_t *) ext2_inactive },
+	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
+	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
+	{ &vop_print_desc,		(vop_t *) ext2_print },
+	{ &vop_read_desc,		(vop_t *) ext2spec_read },
+	{ &vop_reclaim_desc,		(vop_t *) ext2_reclaim },
+	{ &vop_setattr_desc,		(vop_t *) ext2_setattr },
+	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
+	{ &vop_write_desc,		(vop_t *) ext2spec_write },
 	{ NULL, NULL }
 };
 static struct vnodeopv_desc ext2fs_specop_opv_desc =
@@ -130,9 +188,21 @@ static struct vnodeopv_desc ext2fs_specop_opv_desc =
 
 vop_t **ext2_fifoop_p;
 static struct vnodeopv_entry_desc ext2_fifoop_entries[] = {
-	{ &vop_default_desc,		(vop_t *) ufs_vnoperatefifo },
+	{ &vop_default_desc,		(vop_t *) fifo_vnoperate },
+	{ &vop_access_desc,		(vop_t *) ext2_access },
+	{ &vop_close_desc,		(vop_t *) ext2fifo_close },
 	{ &vop_fsync_desc,		(vop_t *) ext2_fsync },
+	{ &vop_getattr_desc,		(vop_t *) ext2_getattr },
 	{ &vop_inactive_desc,		(vop_t *) ext2_inactive },
+	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
+	{ &vop_kqfilter_desc,		(vop_t *) ext2fifo_kqfilter },
+	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
+	{ &vop_print_desc,		(vop_t *) ext2_print },
+	{ &vop_read_desc,		(vop_t *) ext2fifo_read },
+	{ &vop_reclaim_desc,		(vop_t *) ext2_reclaim },
+	{ &vop_setattr_desc,		(vop_t *) ext2_setattr },
+	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
+	{ &vop_write_desc,		(vop_t *) ext2fifo_write },
 	{ NULL, NULL }
 };
 static struct vnodeopv_desc ext2fs_fifoop_opv_desc =
@@ -144,9 +214,26 @@ static struct vnodeopv_desc ext2fs_fifoop_opv_desc =
 
 #include <gnu/ext2fs/ext2_readwrite.c>
 
+union _qcvt {
+	int64_t qcvt;
+	int32_t val[2];
+};
+#define SETHIGH(q, h) { \
+	union _qcvt tmp; \
+	tmp.qcvt = (q); \
+	tmp.val[_QUAD_HIGHWORD] = (h); \
+	(q) = tmp.qcvt; \
+}
+#define SETLOW(q, l) { \
+	union _qcvt tmp; \
+	tmp.qcvt = (q); \
+	tmp.val[_QUAD_LOWWORD] = (l); \
+	(q) = tmp.qcvt; \
+}
+
 /*
  * A virgin directory (no blushing please).
- * Note that the type and namlen fields are reversed relative to ufs.
+ * Note that the type and namlen fields are reversed relative to ext2.
  * Also, we don't use `struct odirtemplate', since it would just cause
  * endianness problems.
  */
@@ -159,6 +246,39 @@ static struct dirtemplate omastertemplate = {
 	0, DIRBLKSIZ - 12, 2, EXT2_FT_UNKNOWN, ".."
 };
 
+void
+ext2_itimes(vp)
+	struct vnode *vp;
+{
+	struct inode *ip;
+	struct timespec ts;
+
+	ip = VTOI(vp);
+	if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0)
+		return;
+	if ((vp->v_type == VBLK || vp->v_type == VCHR))
+		ip->i_flag |= IN_LAZYMOD;
+	else
+		ip->i_flag |= IN_MODIFIED;
+	if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
+		vfs_timestamp(&ts);
+		if (ip->i_flag & IN_ACCESS) {
+			ip->i_atime = ts.tv_sec;
+			ip->i_atimensec = ts.tv_nsec;
+		}
+		if (ip->i_flag & IN_UPDATE) {
+			ip->i_mtime = ts.tv_sec;
+			ip->i_mtimensec = ts.tv_nsec;
+			ip->i_modrev++;
+		}
+		if (ip->i_flag & IN_CHANGE) {
+			ip->i_ctime = ts.tv_sec;
+			ip->i_ctimensec = ts.tv_nsec;
+		}
+	}
+	ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);
+}
+
 /*
  * Create a regular file
  */
@@ -181,6 +301,375 @@ ext2_create(ap)
 	return (0);
 }
 
+/*
+ * Open called.
+ *
+ * Nothing to do.
+ */
+int
+ext2_open(ap)
+	struct vop_open_args /* {
+		struct vnode *a_vp;
+		int  a_mode;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+
+	/*
+	 * Files marked append-only must be opened for appending.
+	 */
+	if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
+	    (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
+		return (EPERM);
+	return (0);
+}
+
+/*
+ * Close called.
+ *
+ * Update the times on the inode.
+ */
+static int
+ext2_close(ap)
+	struct vop_close_args /* {
+		struct vnode *a_vp;
+		int  a_fflag;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+	struct mount *mp;
+
+	mtx_lock(&vp->v_interlock);
+	if (vp->v_usecount > 1) {
+		ext2_itimes(vp);
+		mtx_unlock(&vp->v_interlock);
+	} else {
+		mtx_unlock(&vp->v_interlock);
+		/*
+		 * If we are closing the last reference to an unlinked
+		 * file, then it will be freed by the inactive routine.
+		 * Because the freeing causes a the filesystem to be
+		 * modified, it must be held up during periods when the
+		 * filesystem is suspended.
+		 *
+		 * XXX - EAGAIN is returned to prevent vn_close from
+		 * repeating the vrele operation.
+		 */
+		if (vp->v_type == VREG && VTOI(vp)->i_nlink == 0) {
+			(void) vn_start_write(vp, &mp, V_WAIT);
+			vrele(vp);
+			vn_finished_write(mp);
+			return (EAGAIN);
+		}
+	}
+	return (0);
+}
+
+static int
+ext2_access(ap)
+	struct vop_access_args /* {
+		struct vnode *a_vp;
+		int  a_mode;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
+	mode_t mode = ap->a_mode;
+	int error;
+
+	/*
+	 * Disallow write attempts on read-only file systems;
+	 * unless the file is a socket, fifo, or a block or
+	 * character device resident on the file system.
+	 */
+	if (mode & VWRITE) {
+		switch (vp->v_type) {
+		case VDIR:
+		case VLNK:
+		case VREG:
+			if (vp->v_mount->mnt_flag & MNT_RDONLY)
+				return (EROFS);
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* If immutable bit set, nobody gets to write it. */
+	if ((mode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT)))
+		return (EPERM);
+
+	error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid,
+	    ap->a_mode, ap->a_cred, NULL);
+	return (error);
+}
+
+static int
+ext2_getattr(ap)
+	struct vop_getattr_args /* {
+		struct vnode *a_vp;
+		struct vattr *a_vap;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
+	struct vattr *vap = ap->a_vap;
+
+	ext2_itimes(vp);
+	/*
+	 * Copy from inode table
+	 */
+	vap->va_fsid = dev2udev(ip->i_dev);
+	vap->va_fileid = ip->i_number;
+	vap->va_mode = ip->i_mode & ~IFMT;
+	vap->va_nlink = ip->i_nlink;
+	vap->va_uid = ip->i_uid;
+	vap->va_gid = ip->i_gid;
+	vap->va_rdev = ip->i_rdev;
+	vap->va_size = ip->i_size;
+	vap->va_atime.tv_sec = ip->i_atime;
+	vap->va_atime.tv_nsec = ip->i_atimensec;
+	vap->va_mtime.tv_sec = ip->i_mtime;
+	vap->va_mtime.tv_nsec = ip->i_mtimensec;
+	vap->va_ctime.tv_sec = ip->i_ctime;
+	vap->va_ctime.tv_nsec = ip->i_ctimensec;
+	vap->va_flags = ip->i_flags;
+	vap->va_gen = ip->i_gen;
+	vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
+	vap->va_bytes = dbtob((u_quad_t)ip->i_blocks);
+	vap->va_type = IFTOVT(ip->i_mode);
+	vap->va_filerev = ip->i_modrev;
+	return (0);
+}
+
+/*
+ * Set attribute vnode op. called from several syscalls
+ */
+int
+ext2_setattr(ap)
+	struct vop_setattr_args /* {
+		struct vnode *a_vp;
+		struct vattr *a_vap;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct vattr *vap = ap->a_vap;
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
+	struct ucred *cred = ap->a_cred;
+	struct thread *td = ap->a_td;
+	int error;
+
+	/*
+	 * Check for unsettable attributes.
+	 */
+	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
+	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
+	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
+	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
+		return (EINVAL);
+	}
+	if (vap->va_flags != VNOVAL) {
+		if (vp->v_mount->mnt_flag & MNT_RDONLY)
+			return (EROFS);
+		/*
+		 * Callers may only modify the file flags on objects they
+		 * have VADMIN rights for.
+		 */
+		if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
+			return (error);
+		/*
+		 * Unprivileged processes and privileged processes in
+		 * jail() are not permitted to unset system flags, or
+		 * modify flags if any system flags are set.
+		 * Privileged non-jail processes may not modify system flags
+		 * if securelevel > 0 and any existing system flags are set.
+		 */
+		if (!suser_cred(cred, PRISON_ROOT)) {
+			if (ip->i_flags
+			    & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) {
+				error = securelevel_gt(cred, 0);
+				if (error)
+					return (error);
+			}
+			ip->i_flags = vap->va_flags;
+		} else {
+			if (ip->i_flags
+			    & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) ||
+			    (vap->va_flags & UF_SETTABLE) != vap->va_flags)
+				return (EPERM);
+			ip->i_flags &= SF_SETTABLE;
+			ip->i_flags |= (vap->va_flags & UF_SETTABLE);
+		}
+		ip->i_flag |= IN_CHANGE;
+		if (vap->va_flags & (IMMUTABLE | APPEND))
+			return (0);
+	}
+	if (ip->i_flags & (IMMUTABLE | APPEND))
+		return (EPERM);
+	/*
+	 * Go through the fields and update iff not VNOVAL.
+	 */
+	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
+		if (vp->v_mount->mnt_flag & MNT_RDONLY)
+			return (EROFS);
+		if ((error = ext2_chown(vp, vap->va_uid, vap->va_gid, cred,
+		    td)) != 0)
+			return (error);
+	}
+	if (vap->va_size != VNOVAL) {
+		/*
+		 * Disallow write attempts on read-only file systems;
+		 * unless the file is a socket, fifo, or a block or
+		 * character device resident on the file system.
+		 */
+		switch (vp->v_type) {
+		case VDIR:
+			return (EISDIR);
+		case VLNK:
+		case VREG:
+			if (vp->v_mount->mnt_flag & MNT_RDONLY)
+				return (EROFS);
+			break;
+		default:
+			break;
+		}
+		if ((error = ext2_truncate(vp, vap->va_size, 0, cred, td)) != 0)
+			return (error);
+	}
+	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+		if (vp->v_mount->mnt_flag & MNT_RDONLY)
+			return (EROFS);
+		/*
+		 * From utimes(2):
+		 * If times is NULL, ... The caller must be the owner of
+		 * the file, have permission to write the file, or be the
+		 * super-user.
+		 * If times is non-NULL, ... The caller must be the owner of
+		 * the file or be the super-user.
+		 */
+		if ((error = VOP_ACCESS(vp, VADMIN, cred, td)) &&
+		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
+		    (error = VOP_ACCESS(vp, VWRITE, cred, td))))
+			return (error);
+		if (vap->va_atime.tv_sec != VNOVAL)
+			ip->i_flag |= IN_ACCESS;
+		if (vap->va_mtime.tv_sec != VNOVAL)
+			ip->i_flag |= IN_CHANGE | IN_UPDATE;
+		ext2_itimes(vp);
+		if (vap->va_atime.tv_sec != VNOVAL) {
+			ip->i_atime = vap->va_atime.tv_sec;
+			ip->i_atimensec = vap->va_atime.tv_nsec;
+		}
+		if (vap->va_mtime.tv_sec != VNOVAL) {
+			ip->i_mtime = vap->va_mtime.tv_sec;
+			ip->i_mtimensec = vap->va_mtime.tv_nsec;
+		}
+		error = ext2_update(vp, 0);
+		if (error)
+			return (error);
+	}
+	error = 0;
+	if (vap->va_mode != (mode_t)VNOVAL) {
+		if (vp->v_mount->mnt_flag & MNT_RDONLY)
+			return (EROFS);
+		error = ext2_chmod(vp, (int)vap->va_mode, cred, td);
+	}
+	VN_KNOTE(vp, NOTE_ATTRIB);
+	return (error);
+}
+
+/*
+ * Change the mode on a file.
+ * Inode must be locked before calling.
+ */
+static int
+ext2_chmod(vp, mode, cred, td)
+	struct vnode *vp;
+	int mode;
+	struct ucred *cred;
+	struct thread *td;
+{
+	struct inode *ip = VTOI(vp);
+	int error;
+
+	/*
+	 * To modify the permissions on a file, must possess VADMIN
+	 * for that file.
+	 */
+	if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
+		return (error);
+	/*
+	 * Privileged processes may set the sticky bit on non-directories,
+	 * as well as set the setgid bit on a file with a group that the
+	 * process is not a member of.
+	 */
+	if (suser_cred(cred, PRISON_ROOT)) {
+		if (vp->v_type != VDIR && (mode & S_ISTXT))
+			return (EFTYPE);
+		if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
+			return (EPERM);
+	}
+	ip->i_mode &= ~ALLPERMS;
+	ip->i_mode |= (mode & ALLPERMS);
+	ip->i_flag |= IN_CHANGE;
+	return (0);
+}
+
+/*
+ * Perform chown operation on inode ip;
+ * inode must be locked prior to call.
+ */
+static int
+ext2_chown(vp, uid, gid, cred, td)
+	struct vnode *vp;
+	uid_t uid;
+	gid_t gid;
+	struct ucred *cred;
+	struct thread *td;
+{
+	struct inode *ip = VTOI(vp);
+	uid_t ouid;
+	gid_t ogid;
+	int error = 0;
+
+	if (uid == (uid_t)VNOVAL)
+		uid = ip->i_uid;
+	if (gid == (gid_t)VNOVAL)
+		gid = ip->i_gid;
+	/*
+	 * To modify the ownership of a file, must possess VADMIN
+	 * for that file.
+	 */
+	if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
+		return (error);
+	/*
+	 * To change the owner of a file, or change the group of a file
+	 * to a group of which we are not a member, the caller must
+	 * have privilege.
+	 */
+	if ((uid != ip->i_uid || 
+	    (gid != ip->i_gid && !groupmember(gid, cred))) &&
+	    (error = suser_cred(cred, PRISON_ROOT)))
+		return (error);
+	ogid = ip->i_gid;
+	ouid = ip->i_uid;
+	ip->i_gid = gid;
+	ip->i_uid = uid;
+	ip->i_flag |= IN_CHANGE;
+	if (suser_cred(cred, PRISON_ROOT) && (ouid != uid || ogid != gid))
+		ip->i_mode &= ~(ISUID | ISGID);
+	return (0);
+}
+
 /*
  * Synch an open file.
  */
@@ -241,7 +730,7 @@ loop:
 #endif
 	}
 	splx(s);
-	return (UFS_UPDATE(ap->a_vp, ap->a_waitfor == MNT_WAIT));
+	return (ext2_update(ap->a_vp, ap->a_waitfor == MNT_WAIT));
 }
 
 /*
@@ -341,7 +830,7 @@ ext2_link(ap)
 
 #ifdef DIAGNOSTIC
 	if ((cnp->cn_flags & HASBUF) == 0)
-		panic("ufs_link: no name");
+		panic("ext2_link: no name");
 #endif
 	if (tdvp->v_mount != vp->v_mount) {
 		error = EXDEV;
@@ -361,7 +850,7 @@ ext2_link(ap)
 	}
 	ip->i_nlink++;
 	ip->i_flag |= IN_CHANGE;
-	error = UFS_UPDATE(vp, 1);
+	error = ext2_update(vp, 1);
 	if (!error)
 		error = ext2_direnter(ip, tdvp, cnp);
 	if (error) {
@@ -406,7 +895,7 @@ ext2_rename(ap)
 #ifdef DIAGNOSTIC
 	if ((tcnp->cn_flags & HASBUF) == 0 ||
 	    (fcnp->cn_flags & HASBUF) == 0)
-		panic("ufs_rename: no name");
+		panic("ext2_rename: no name");
 #endif
 	/*
 	 * Check for cross-device rename.
@@ -447,7 +936,7 @@ abortit:
 			 * completed before the lookup.
 			 */
 #ifdef UFS_RENAME_DEBUG
-			printf("ufs_rename: fvp == tvp for directories\n");
+			printf("ext2_rename: fvp == tvp for directories\n");
 #endif
 			error = ENOENT;
 			goto abortit;
@@ -474,7 +963,7 @@ abortit:
 			vrele(fdvp);
 		if (fvp == NULL) {
 #ifdef UFS_RENAME_DEBUG
-			printf("ufs_rename: from name disappeared\n");
+			printf("ext2_rename: from name disappeared\n");
 #endif
 			return (ENOENT);
 		}
@@ -536,7 +1025,7 @@ abortit:
 	 */
 	ip->i_nlink++;
 	ip->i_flag |= IN_CHANGE;
-	if ((error = UFS_UPDATE(fvp, 1)) != 0) {
+	if ((error = ext2_update(fvp, 1)) != 0) {
 		VOP_UNLOCK(fvp, 0, td);
 		goto bad;
 	}
@@ -582,7 +1071,7 @@ abortit:
 	 */
 	if (xp == NULL) {
 		if (dp->i_dev != ip->i_dev)
-			panic("ufs_rename: EXDEV");
+			panic("ext2_rename: EXDEV");
 		/*
 		 * Account for ".." in new directory.
 		 * When source and destination have the same
@@ -595,7 +1084,7 @@ abortit:
 			}
 			dp->i_nlink++;
 			dp->i_flag |= IN_CHANGE;
-			error = UFS_UPDATE(tdvp, 1);
+			error = ext2_update(tdvp, 1);
 			if (error)
 				goto bad;
 		}
@@ -604,19 +1093,19 @@ abortit:
 			if (doingdirectory && newparent) {
 				dp->i_nlink--;
 				dp->i_flag |= IN_CHANGE;
-				(void)UFS_UPDATE(tdvp, 1);
+				(void)ext2_update(tdvp, 1);
 			}
 			goto bad;
 		}
 		vput(tdvp);
 	} else {
 		if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
-			panic("ufs_rename: EXDEV");
+			panic("ext2_rename: EXDEV");
 		/*
 		 * Short circuit rename(foo, foo).
 		 */
 		if (xp->i_number == ip->i_number)
-			panic("ufs_rename: same file");
+			panic("ext2_rename: same file");
 		/*
 		 * If the parent directory is "sticky", then the user must
 		 * own the parent directory, or the destination of the rename,
@@ -676,8 +1165,8 @@ abortit:
 		xp->i_nlink--;
 		if (doingdirectory) {
 			if (--xp->i_nlink != 0)
-				panic("ufs_rename: linked directory");
-			error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC,
+				panic("ext2_rename: linked directory");
+			error = ext2_truncate(tvp, (off_t)0, IO_SYNC,
 			    tcnp->cn_cred, tcnp->cn_thread);
 		}
 		xp->i_flag |= IN_CHANGE;
@@ -702,7 +1191,7 @@ abortit:
 		 * From name has disappeared.
 		 */
 		if (doingdirectory)
-			panic("ufs_rename: lost dir entry");
+			panic("ext2_rename: lost dir entry");
 		vrele(ap->a_fvp);
 		return (0);
 	}
@@ -718,7 +1207,7 @@ abortit:
 	 */
 	if (xp != ip) {
 		if (doingdirectory)
-			panic("ufs_rename: lost dir entry");
+			panic("ext2_rename: lost dir entry");
 	} else {
 		/*
 		 * If the source is a directory with a
@@ -739,7 +1228,7 @@ abortit:
 				if (namlen != 2 ||
 				    dirbuf.dotdot_name[0] != '.' ||
 				    dirbuf.dotdot_name[1] != '.') {
-					ufs_dirbad(xp, (doff_t)12,
+					ext2_dirbad(xp, (doff_t)12,
 					    "rename: mangled dir");
 				} else {
 					dirbuf.dotdot_ino = newparent;
@@ -807,7 +1296,7 @@ ext2_mkdir(ap)
 
 #ifdef DIAGNOSTIC
 	if ((cnp->cn_flags & HASBUF) == 0)
-		panic("ufs_mkdir: no name");
+		panic("ext2_mkdir: no name");
 #endif
 	dp = VTOI(dvp);
 	if ((nlink_t)dp->i_nlink >= LINK_MAX) {
@@ -821,17 +1310,13 @@ ext2_mkdir(ap)
 	 * but not have it entered in the parent directory. The entry is
 	 * made later after writing "." and ".." entries.
 	 */
-	error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp);
+	error = ext2_valloc(dvp, dmode, cnp->cn_cred, &tvp);
 	if (error)
 		goto out;
 	ip = VTOI(tvp);
 	ip->i_gid = dp->i_gid;
 #ifdef SUIDDIR
 	{
-#ifdef QUOTA
-		struct ucred ucred, *ucp;
-		ucp = cnp->cn_cred;
-#endif
 		/*
 		 * if we are hacking owners here, (only do this where told to)
 		 * and we are not giving it TOO root, (would subvert quotas)
@@ -844,44 +1329,12 @@ ext2_mkdir(ap)
 		   (dp->i_mode & ISUID) && dp->i_uid) {
 			dmode |= ISUID;
 			ip->i_uid = dp->i_uid;
-#ifdef QUOTA
-			if (dp->i_uid != cnp->cn_cred->cr_uid) {
-				/*
-				 * make sure the correct user gets charged
-				 * for the space.
-				 * Make a dummy credential for the victim.
-				 * XXX This seems to never be accessed out of
-				 * our context so a stack variable is ok.
-				 */
-				ucred.cr_ref = 1;
-				ucred.cr_uid = ip->i_uid;
-				ucred.cr_ngroups = 1;
-				ucred.cr_groups[0] = dp->i_gid;
-				ucp = &ucred;
-			}
-#endif
 		} else {
 			ip->i_uid = cnp->cn_cred->cr_uid;
 		}
-#ifdef QUOTA
-		if ((error = getinoquota(ip)) ||
-	    	(error = chkiq(ip, 1, ucp, 0))) {
-			UFS_VFREE(tvp, ip->i_number, dmode);
-			vput(tvp);
-			return (error);
-		}
-#endif
 	}
 #else
 	ip->i_uid = cnp->cn_cred->cr_uid;
-#ifdef QUOTA
-	if ((error = getinoquota(ip)) ||
-	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
-		UFS_VFREE(tvp, ip->i_number, dmode);
-		vput(tvp);
-		return (error);
-	}
-#endif
 #endif
 	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
 	ip->i_mode = dmode;
@@ -889,7 +1342,7 @@ ext2_mkdir(ap)
 	ip->i_nlink = 2;
 	if (cnp->cn_flags & ISWHITEOUT)
 		ip->i_flags |= UF_OPAQUE;
-	error = UFS_UPDATE(tvp, 1);
+	error = ext2_update(tvp, 1);
 
 	/*
 	 * Bump link count in parent directory
@@ -899,7 +1352,7 @@ ext2_mkdir(ap)
 	 */
 	dp->i_nlink++;
 	dp->i_flag |= IN_CHANGE;
-	error = UFS_UPDATE(dvp, 1);
+	error = ext2_update(dvp, 1);
 	if (error)
 		goto bad;
 
@@ -926,8 +1379,9 @@ ext2_mkdir(ap)
 		dp->i_flag |= IN_CHANGE;
 		goto bad;
 	}
-	if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
-		panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
+	if (DIRBLKSIZ > VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
+		/* XXX should grow with balloc() */
+		panic("ext2_mkdir: blksize");
 	else {
 		ip->i_size = DIRBLKSIZ;
 		ip->i_flag |= IN_CHANGE;
@@ -1018,7 +1472,7 @@ ext2_rmdir(ap)
 	 * worry about them later.
 	 */
 	ip->i_nlink -= 2;
-	error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, td);
+	error = ext2_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred, td);
 	cache_purge(ITOV(ip));
 	vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
 out:
@@ -1062,6 +1516,362 @@ ext2_symlink(ap)
 	return (error);
 }
 
+/*
+ * Return target name of a symbolic link
+ */
+static int
+ext2_readlink(ap)
+	struct vop_readlink_args /* {
+		struct vnode *a_vp;
+		struct uio *a_uio;
+		struct ucred *a_cred;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
+	int isize;
+
+	isize = ip->i_size;
+	if (isize < vp->v_mount->mnt_maxsymlinklen) {
+		uiomove((char *)ip->i_shortlink, isize, ap->a_uio);
+		return (0);
+	}
+	return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
+}
+
+/*
+ * Calculate the logical to physical mapping if not done already,
+ * then call the device strategy routine.
+ *
+ * In order to be able to swap to a file, the ext2_bmaparray() operation may not
+ * deadlock on memory.  See ext2_bmap() for details.
+ */
+int
+ext2_strategy(ap)
+	struct vop_strategy_args /* {
+		struct vnode *a_vp;
+		struct buf *a_bp;
+	} */ *ap;
+{
+	struct buf *bp = ap->a_bp;
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip;
+	daddr_t blkno;
+	int error;
+
+	ip = VTOI(vp);
+	if (vp->v_type == VBLK || vp->v_type == VCHR)
+		panic("ext2_strategy: spec");
+	if (bp->b_blkno == bp->b_lblkno) {
+		error = ext2_bmaparray(vp, bp->b_lblkno, &blkno, NULL, NULL);
+		bp->b_blkno = blkno;
+		if (error) {
+			bp->b_error = error;
+			bp->b_ioflags |= BIO_ERROR;
+			bufdone(bp);
+			return (error);
+		}
+		if ((long)bp->b_blkno == -1)
+			vfs_bio_clrbuf(bp);
+	}
+	if ((long)bp->b_blkno == -1) {
+		bufdone(bp);
+		return (0);
+	}
+	vp = ip->i_devvp;
+	bp->b_dev = vp->v_rdev;
+	VOP_STRATEGY(vp, bp);
+	return (0);
+}
+
+/*
+ * Print out the contents of an inode.
+ */
+int
+ext2_print(ap)
+	struct vop_print_args /* {
+		struct vnode *a_vp;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
+
+	printf("tag VT_UFS, ino %lu, on dev %s (%d, %d)",
+	    (u_long)ip->i_number, devtoname(ip->i_dev), major(ip->i_dev),
+	    minor(ip->i_dev));
+	if (vp->v_type == VFIFO)
+		fifo_printinfo(vp);
+	lockmgr_printinfo(&vp->v_lock);
+	printf("\n");
+	return (0);
+}
+
+/*
+ * Read wrapper for special devices.
+ */
+int
+ext2spec_read(ap)
+	struct vop_read_args /* {
+		struct vnode *a_vp;
+		struct uio *a_uio;
+		int  a_ioflag;
+		struct ucred *a_cred;
+	} */ *ap;
+{
+	int error, resid;
+	struct inode *ip;
+	struct uio *uio;
+
+	uio = ap->a_uio;
+	resid = uio->uio_resid;
+	error = VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap);
+	/*
+	 * The inode may have been revoked during the call, so it must not
+	 * be accessed blindly here or in the other wrapper functions.
+	 */
+	ip = VTOI(ap->a_vp);
+	if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
+		ip->i_flag |= IN_ACCESS;
+	return (error);
+}
+
+/*
+ * Write wrapper for special devices.
+ */
+int
+ext2spec_write(ap)
+	struct vop_write_args /* {
+		struct vnode *a_vp;
+		struct uio *a_uio;
+		int  a_ioflag;
+		struct ucred *a_cred;
+	} */ *ap;
+{
+	int error, resid;
+	struct inode *ip;
+	struct uio *uio;
+
+	uio = ap->a_uio;
+	resid = uio->uio_resid;
+	error = VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap);
+	ip = VTOI(ap->a_vp);
+	if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
+		VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
+	return (error);
+}
+
+/*
+ * Close wrapper for special devices.
+ *
+ * Update the times on the inode then do device close.
+ */
+int
+ext2spec_close(ap)
+	struct vop_close_args /* {
+		struct vnode *a_vp;
+		int  a_fflag;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+
+	mtx_lock(&vp->v_interlock);
+	if (vp->v_usecount > 1)
+		ext2_itimes(vp);
+	mtx_unlock(&vp->v_interlock);
+	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
+}
+
+/*
+ * Read wrapper for fifos.
+ */
+int
+ext2fifo_read(ap)
+	struct vop_read_args /* {
+		struct vnode *a_vp;
+		struct uio *a_uio;
+		int  a_ioflag;
+		struct ucred *a_cred;
+	} */ *ap;
+{
+	int error, resid;
+	struct inode *ip;
+	struct uio *uio;
+
+	uio = ap->a_uio;
+	resid = uio->uio_resid;
+	error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap);
+	ip = VTOI(ap->a_vp);
+	if ((ap->a_vp->v_mount->mnt_flag & MNT_NOATIME) == 0 && ip != NULL &&
+	    (uio->uio_resid != resid || (error == 0 && resid != 0)))
+		VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
+	return (error);
+}
+
+/*
+ * Write wrapper for fifos.
+ */
+int
+ext2fifo_write(ap)
+	struct vop_write_args /* {
+		struct vnode *a_vp;
+		struct uio *a_uio;
+		int  a_ioflag;
+		struct ucred *a_cred;
+	} */ *ap;
+{
+	int error, resid;
+	struct inode *ip;
+	struct uio *uio;
+
+	uio = ap->a_uio;
+	resid = uio->uio_resid;
+	error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap);
+	ip = VTOI(ap->a_vp);
+	if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
+		VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
+	return (error);
+}
+
+/*
+ * Close wrapper for fifos.
+ *
+ * Update the times on the inode then do device close.
+ */
+int
+ext2fifo_close(ap)
+	struct vop_close_args /* {
+		struct vnode *a_vp;
+		int  a_fflag;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+
+	mtx_lock(&vp->v_interlock);
+	if (vp->v_usecount > 1)
+		ext2_itimes(vp);
+	mtx_unlock(&vp->v_interlock);
+	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
+}
+
+/*
+ * Kqfilter wrapper for fifos.
+ *
+ * Fall through to ext2 kqfilter routines if needed 
+ */
+int
+ext2fifo_kqfilter(ap)
+	struct vop_kqfilter_args *ap;
+{
+	int error;
+
+	error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_kqfilter), ap);
+	if (error)
+		error = ext2_kqfilter(ap);
+	return (error);
+}
+
+/*
+ * Return POSIX pathconf information applicable to ext2 filesystems.
+ */
+int
+ext2_pathconf(ap)
+	struct vop_pathconf_args /* {
+		struct vnode *a_vp;
+		int a_name;
+		int *a_retval;
+	} */ *ap;
+{
+
+	switch (ap->a_name) {
+	case _PC_LINK_MAX:
+		*ap->a_retval = LINK_MAX;
+		return (0);
+	case _PC_NAME_MAX:
+		*ap->a_retval = NAME_MAX;
+		return (0);
+	case _PC_PATH_MAX:
+		*ap->a_retval = PATH_MAX;
+		return (0);
+	case _PC_PIPE_BUF:
+		*ap->a_retval = PIPE_BUF;
+		return (0);
+	case _PC_CHOWN_RESTRICTED:
+		*ap->a_retval = 1;
+		return (0);
+	case _PC_NO_TRUNC:
+		*ap->a_retval = 1;
+		return (0);
+	default:
+		return (EINVAL);
+	}
+	/* NOTREACHED */
+}
+
+/*
+ * Advisory record locking support
+ */
+static int
+ext2_advlock(ap)
+	struct vop_advlock_args /* {
+		struct vnode *a_vp;
+		caddr_t  a_id;
+		int  a_op;
+		struct flock *a_fl;
+		int  a_flags;
+	} */ *ap;
+{
+	struct inode *ip = VTOI(ap->a_vp);
+
+	return (lf_advlock(ap, &(ip->i_lockf), ip->i_size));
+}
+
+/*
+ * Initialize the vnode associated with a new inode, handle aliased
+ * vnodes.
+ */
+int
+ext2_vinit(mntp, specops, fifoops, vpp)
+	struct mount *mntp;
+	vop_t **specops;
+	vop_t **fifoops;
+	struct vnode **vpp;
+{
+	struct inode *ip;
+	struct vnode *vp;
+	struct timeval tv;
+
+	vp = *vpp;
+	ip = VTOI(vp);
+	switch(vp->v_type = IFTOVT(ip->i_mode)) {
+	case VCHR:
+	case VBLK:
+		vp->v_op = specops;
+		vp = addaliasu(vp, ip->i_rdev);
+		ip->i_vnode = vp;
+		break;
+	case VFIFO:
+		vp->v_op = fifoops;
+		break;
+	default:
+		break;
+
+	}
+	if (ip->i_number == ROOTINO)
+		vp->v_flag |= VROOT;
+	/*
+	 * Initialize modrev times
+	 */
+	getmicrouptime(&tv);
+	SETHIGH(ip->i_modrev, tv.tv_sec);
+	SETLOW(ip->i_modrev, tv.tv_usec * 4294);
+	*vpp = vp;
+	return (0);
+}
+
 /*
  * Allocate a new inode.
  */
@@ -1085,7 +1895,7 @@ ext2_makeinode(mode, dvp, vpp, cnp)
 	if ((mode & IFMT) == 0)
 		mode |= IFREG;
 
-	error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp);
+	error = ext2_valloc(dvp, mode, cnp->cn_cred, &tvp);
 	if (error) {
 		return (error);
 	}
@@ -1093,10 +1903,6 @@ ext2_makeinode(mode, dvp, vpp, cnp)
 	ip->i_gid = pdir->i_gid;
 #ifdef SUIDDIR
 	{
-#ifdef QUOTA
-		struct ucred ucred, *ucp;
-		ucp = cnp->cn_cred;
-#endif
 		/*
 		 * if we are
 		 * not the owner of the directory,
@@ -1110,43 +1916,12 @@ ext2_makeinode(mode, dvp, vpp, cnp)
 		     (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) {
 			ip->i_uid = pdir->i_uid;
 			mode &= ~07111;
-#ifdef QUOTA
-			/*
-			 * make sure the correct user gets charged
-			 * for the space.
-			 * Quickly knock up a dummy credential for the victim.
-			 * XXX This seems to never be accessed out of our
-			 * context so a stack variable is ok.
-			 */
-			ucred.cr_ref = 1;
-			ucred.cr_uid = ip->i_uid;
-			ucred.cr_ngroups = 1;
-			ucred.cr_groups[0] = pdir->i_gid;
-			ucp = &ucred;
-#endif
 		} else {
 			ip->i_uid = cnp->cn_cred->cr_uid;
 		}
-	
-#ifdef QUOTA
-		if ((error = getinoquota(ip)) ||
-	    	(error = chkiq(ip, 1, ucp, 0))) {
-			UFS_VFREE(tvp, ip->i_number, mode);
-			vput(tvp);
-			return (error);
-		}
-#endif
 	}
 #else
 	ip->i_uid = cnp->cn_cred->cr_uid;
-#ifdef QUOTA
-	if ((error = getinoquota(ip)) ||
-	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
-		UFS_VFREE(tvp, ip->i_number, mode);
-		vput(tvp);
-		return (error);
-	}
-#endif
 #endif
 	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
 	ip->i_mode = mode;
@@ -1162,7 +1937,7 @@ ext2_makeinode(mode, dvp, vpp, cnp)
 	/*
 	 * Make sure inode goes to disk before directory entry.
 	 */
-	error = UFS_UPDATE(tvp, 1);
+	error = ext2_update(tvp, 1);
 	if (error)
 		goto bad;
 	error = ext2_direnter(ip, dvp, cnp);
@@ -1182,3 +1957,106 @@ bad:
 	vput(tvp);
 	return (error);
 }
+
+static struct filterops ext2read_filtops = 
+	{ 1, NULL, filt_ext2detach, filt_ext2read };
+static struct filterops ext2write_filtops = 
+	{ 1, NULL, filt_ext2detach, filt_ext2write };
+static struct filterops ext2vnode_filtops = 
+	{ 1, NULL, filt_ext2detach, filt_ext2vnode };
+
+static int
+ext2_kqfilter(ap)
+	struct vop_kqfilter_args /* {
+		struct vnode *a_vp;
+		struct knote *a_kn;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+	struct knote *kn = ap->a_kn;
+
+	switch (kn->kn_filter) {
+	case EVFILT_READ:
+		kn->kn_fop = &ext2read_filtops;
+		break;
+	case EVFILT_WRITE:
+		kn->kn_fop = &ext2write_filtops;
+		break;
+	case EVFILT_VNODE:
+		kn->kn_fop = &ext2vnode_filtops;
+		break;
+	default:
+		return (1);
+	}
+
+	kn->kn_hook = (caddr_t)vp;
+
+	if (vp->v_pollinfo == NULL)
+		v_addpollinfo(vp);
+	mtx_lock(&vp->v_pollinfo->vpi_lock);
+	SLIST_INSERT_HEAD(&vp->v_pollinfo->vpi_selinfo.si_note, kn, kn_selnext);
+	mtx_unlock(&vp->v_pollinfo->vpi_lock);
+
+	return (0);
+}
+
+static void
+filt_ext2detach(struct knote *kn)
+{
+	struct vnode *vp = (struct vnode *)kn->kn_hook;
+
+	KASSERT(vp->v_pollinfo != NULL, ("Mising v_pollinfo"));
+	mtx_lock(&vp->v_pollinfo->vpi_lock);
+	SLIST_REMOVE(&vp->v_pollinfo->vpi_selinfo.si_note,
+	    kn, knote, kn_selnext);
+	mtx_unlock(&vp->v_pollinfo->vpi_lock);
+}
+
+/*ARGSUSED*/
+static int
+filt_ext2read(struct knote *kn, long hint)
+{
+	struct vnode *vp = (struct vnode *)kn->kn_hook;
+	struct inode *ip = VTOI(vp);
+
+	/*
+	 * filesystem is gone, so set the EOF flag and schedule 
+	 * the knote for deletion.
+	 */
+	if (hint == NOTE_REVOKE) {
+		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
+		return (1);
+	}
+
+        kn->kn_data = ip->i_size - kn->kn_fp->f_offset;
+        return (kn->kn_data != 0);
+}
+
+/*ARGSUSED*/
+static int
+filt_ext2write(struct knote *kn, long hint)
+{
+
+	/*
+	 * filesystem is gone, so set the EOF flag and schedule 
+	 * the knote for deletion.
+	 */
+	if (hint == NOTE_REVOKE)
+		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
+
+        kn->kn_data = 0;
+        return (1);
+}
+
+static int
+filt_ext2vnode(struct knote *kn, long hint)
+{
+
+	if (kn->kn_sfflags & hint)
+		kn->kn_fflags |= hint;
+	if (hint == NOTE_REVOKE) {
+		kn->kn_flags |= EV_EOF;
+		return (1);
+	}
+	return (kn->kn_fflags != 0);
+}
diff --git a/sys/gnu/ext2fs/fs.h b/sys/gnu/ext2fs/fs.h
index 785f267f8ac3..50fb711f371f 100644
--- a/sys/gnu/ext2fs/fs.h
+++ b/sys/gnu/ext2fs/fs.h
@@ -148,7 +148,7 @@ extern u_char *fragtbl[];
  * I haven't figured out yet what BSD does
  * I think I'll try a VOP_LOCK/VOP_UNLOCK on the device vnode
  */
-#define  DEVVP(inode)		(VFSTOUFS(ITOV(inode)->v_mount)->um_devvp)
+#define  DEVVP(inode)		(VFSTOEXT2(ITOV(inode)->v_mount)->um_devvp)
 #define  lock_super(devvp)   	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, curthread)
 #define  unlock_super(devvp) 	VOP_UNLOCK(devvp, 0, curthread)
 
diff --git a/sys/gnu/fs/ext2fs/ext2_alloc.c b/sys/gnu/fs/ext2fs/ext2_alloc.c
index b9c40d37b9e1..585c5cdb4632 100644
--- a/sys/gnu/fs/ext2fs/ext2_alloc.c
+++ b/sys/gnu/fs/ext2fs/ext2_alloc.c
@@ -40,8 +40,6 @@
  * $FreeBSD$
  */
 
-#include "opt_quota.h"
-
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/conf.h>
@@ -50,11 +48,8 @@
 #include <sys/mount.h>
 #include <sys/syslog.h>
 
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-#include <ufs/ufs/ufsmount.h>
-
+#include <gnu/ext2fs/inode.h>
+#include <gnu/ext2fs/ext2_mount.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
 #include <gnu/ext2fs/fs.h>
@@ -108,9 +103,6 @@ ext2_alloc(ip, lbn, bpref, size, cred, bnp)
 {
 	register struct ext2_sb_info *fs;
 	daddr_t bno;
-#if QUOTA
-	int error;
-#endif
 	
 	*bnp = 0;
 	fs = ip->i_e2fs;
@@ -128,10 +120,6 @@ ext2_alloc(ip, lbn, bpref, size, cred, bnp)
 	if (cred->cr_uid != 0 && 
 		fs->s_es->s_free_blocks_count < fs->s_es->s_r_blocks_count)
 		goto nospace;
-#if QUOTA
-	if ((error = chkdq(ip, (long)btodb(size), cred, 0)) != 0)
-		return (error);
-#endif
 	if (bpref >= fs->s_es->s_blocks_count)
 		bpref = 0;
 	/* call the Linux code */
@@ -179,12 +167,6 @@ ext2_alloc(ip, lbn, bpref, size, cred, bnp)
 		*bnp = bno;
 		return (0);
 	}
-#if QUOTA
-	/*
-	 * Restore user's disk quota because allocation failed.
-	 */
-	(void) chkdq(ip, (long)-btodb(size), cred, FORCE);
-#endif
 nospace:
 	ext2_fserr(fs, cred->cr_uid, "file system full");
 	uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
@@ -342,7 +324,7 @@ return ENOSPC;
 	} else {
 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
 		if (!doasyncfree)
-			UFS_UPDATE(vp, 1);
+			ext2_update(vp, 1);
 	}
 	if (ssize < len)
 		if (doasyncfree)
@@ -401,7 +383,7 @@ ext2_valloc(pvp, mode, cred, vpp)
 		goto noinodes;
 	error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp);
 	if (error) {
-		UFS_VFREE(pvp, ino, mode);
+		ext2_vfree(pvp, ino, mode);
 		return (error);
 	}
 	ip = VTOI(*vpp);
diff --git a/sys/gnu/fs/ext2fs/ext2_balloc.c b/sys/gnu/fs/ext2fs/ext2_balloc.c
index 275849fcec52..252a29792527 100644
--- a/sys/gnu/fs/ext2fs/ext2_balloc.c
+++ b/sys/gnu/fs/ext2fs/ext2_balloc.c
@@ -48,10 +48,7 @@
 #include <sys/ucred.h>
 #include <sys/vnode.h>
 
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-#include <ufs/ufs/ufs_extern.h>
-
+#include <gnu/ext2fs/inode.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
 #include <gnu/ext2fs/fs.h>
@@ -164,11 +161,11 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n",
 	 * Determine the number of levels of indirection.
 	 */
 	pref = 0;
-	if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0)
+	if ((error = ext2_getlbns(vp, bn, indirs, &num)) != 0)
 		return(error);
 #if DIAGNOSTIC
 	if (num < 1)
-		panic ("ext2_balloc: ufs_getlbns returned indirect block");
+		panic ("ext2_balloc: ext2_getlbns returned indirect block");
 #endif
 	/*
 	 * Fetch the first indirect block allocating if necessary.
diff --git a/sys/gnu/fs/ext2fs/ext2_extern.h b/sys/gnu/fs/ext2fs/ext2_extern.h
index 8df829b369a7..505fefd97c56 100644
--- a/sys/gnu/fs/ext2fs/ext2_extern.h
+++ b/sys/gnu/fs/ext2fs/ext2_extern.h
@@ -43,8 +43,8 @@
 #ifndef _SYS_GNU_EXT2FS_EXT2_EXTERN_H_
 #define	_SYS_GNU_EXT2FS_EXT2_EXTERN_H_
 
-struct dinode;
 struct ext2_inode;
+struct indir;
 struct inode;
 struct mount;
 struct vfsconf;
@@ -58,7 +58,18 @@ int	ext2_blkatoff(struct vnode *, off_t, char **, struct buf **);
 void	ext2_blkfree(struct inode *, daddr_t, long);
 daddr_t	ext2_blkpref(struct inode *, daddr_t, int, daddr_t *, daddr_t);
 int	ext2_bmap(struct vop_bmap_args *);
-int	ext2_init(struct vfsconf *);
+int	ext2_bmaparray(struct vnode *, daddr_t, daddr_t *, int *, int *);
+void	ext2_dirbad(struct inode *ip, doff_t offset, char *how);
+void	ext2_ei2i(struct ext2_inode *, struct inode *);
+int	ext2_getlbns(struct vnode *, daddr_t, struct indir *, int *);
+void	ext2_i2ei(struct inode *, struct ext2_inode *);
+int	ext2_ihashget(dev_t, ino_t, int, struct vnode **);
+void	ext2_ihashinit(void);
+void	ext2_ihashins(struct inode *);
+struct vnode *
+	ext2_ihashlookup(dev_t, ino_t);
+void	ext2_ihashrem(struct inode *);
+void	ext2_itimes(struct vnode *vp);
 int	ext2_reallocblks(struct vop_reallocblks_args *);
 int	ext2_reclaim(struct vop_reclaim_args *);
 void	ext2_setblock(struct ext2_sb_info *, u_char *, daddr_t);
@@ -66,9 +77,9 @@ int	ext2_truncate(struct vnode *, off_t, int, struct ucred *, struct thread *);
 int	ext2_update(struct vnode *, int);
 int	ext2_valloc(struct vnode *, int, struct ucred *, struct vnode **);
 int	ext2_vfree(struct vnode *, ino_t, int);
+int	ext2_vinit(struct mount *, vop_t **, vop_t **, struct vnode **vpp);
 int 	ext2_lookup(struct vop_cachedlookup_args *);
 int 	ext2_readdir(struct vop_readdir_args *);
-void	ext2_print_dinode(struct dinode *);
 void	ext2_print_inode(struct inode *);
 int	ext2_direnter(struct inode *, 
 		struct vnode *, struct componentname *);
@@ -89,15 +100,13 @@ unsigned long ext2_count_free(struct buf *map, unsigned int numchars);
 void	ext2_free_blocks(struct mount *mp, unsigned long block,
 	    unsigned long count);
 void	ext2_free_inode(struct inode * inode);
-void	ext2_ei2di(struct ext2_inode *ei, struct dinode *di);
-void	ext2_di2ei(struct dinode *di, struct ext2_inode *ei);
 void	mark_buffer_dirty(struct buf *bh);
 
-/*
- * This macro allows the ufs code to distinguish between an EXT2 and a
- * non-ext2(FFS/LFS) vnode.
- */
-#define  IS_EXT2_VNODE(vp) (vp->v_mount->mnt_stat.f_type == MOUNT_EXT2FS)
+/* Flags to low-level allocation routines. */
+#define B_CLRBUF	0x01	/* Request allocated buffer be cleared. */
+#define B_SYNC		0x02	/* Do all allocations synchronously. */
+#define B_METAONLY	0x04	/* Return indirect block buffer. */
+#define B_NOWAIT	0x08	/* do not sleep to await lock */
 
 extern vop_t **ext2_vnodeop_p;
 extern vop_t **ext2_specop_p;
diff --git a/sys/gnu/fs/ext2fs/ext2_fs.h b/sys/gnu/fs/ext2fs/ext2_fs.h
index b5e9f4a92573..29435937181b 100644
--- a/sys/gnu/fs/ext2fs/ext2_fs.h
+++ b/sys/gnu/fs/ext2fs/ext2_fs.h
@@ -38,19 +38,6 @@
 #define umode_t mode_t
 #define loff_t  off_t
 
-/* the Linux implementation of EXT2 stores some information about
- * an inode in a ext2_inode_info structure which is part of the incore
- * inode in Linux
- * I decided to use the "spare" fields instead - we'll see how this
- * works out
- */
-
-#define i_block_group		i_spare[0]
-#define i_next_alloc_block	i_spare[1]
-#define i_next_alloc_goal	i_spare[2]
-#define i_prealloc_block	i_din.di_spare[0]
-#define i_prealloc_count	i_din.di_spare[1]
-
 /*
  * The second extended filesystem constants/structures
  */
@@ -263,14 +250,6 @@ struct ext2_group_desc
 #define	EXT2_IOC_GETVERSION		_IOR('v', 1, long)
 #define	EXT2_IOC_SETVERSION		_IOW('v', 2, long)
 
-/*
- * Only declare `struct ext2_inode' if <ufs/ufs/inode.h> hasn't made things
- * difficult by #defining i_mode and other struct members.  The details of
- * the struct are only needed in ext2_inode_cnv.c where the ext2fs on-disk
- * inode is converted to a ufs in-core inode.
- */
-#ifndef i_mode
-
 /*
  * Structure of an inode on the disk
  */
@@ -351,8 +330,6 @@ struct ext2_inode {
 #define i_reserved2	osd2.masix2.m_i_reserved2
 #endif
 
-#endif /* i_mode */
-
 /*
  * File system states
  */
diff --git a/sys/gnu/fs/ext2fs/ext2_inode.c b/sys/gnu/fs/ext2fs/ext2_inode.c
index 2f0aed472f09..207778c84f88 100644
--- a/sys/gnu/fs/ext2fs/ext2_inode.c
+++ b/sys/gnu/fs/ext2fs/ext2_inode.c
@@ -40,8 +40,6 @@
  * $FreeBSD$
  */
 
-#include "opt_quota.h"
-
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/mount.h>
@@ -53,12 +51,8 @@
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-#include <ufs/ufs/ufsmount.h>
-#include <ufs/ufs/ufs_extern.h>
-
+#include <gnu/ext2fs/inode.h>
+#include <gnu/ext2fs/ext2_mount.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
 #include <gnu/ext2fs/fs.h>
@@ -67,12 +61,6 @@
 static int ext2_indirtrunc(struct inode *, daddr_t, daddr_t, daddr_t, int,
 	    long *);
 
-int
-ext2_init(struct vfsconf *vfsp)
-{
-	return (ufs_init(vfsp));
-}
-
 /*
  * Update the access, modified, and inode change times as specified by the
  * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively.  Write the inode
@@ -92,7 +80,7 @@ ext2_update(vp, waitfor)
 	struct inode *ip;
 	int error;
 
-	ufs_itimes(vp);
+	ext2_itimes(vp);
 	ip = VTOI(vp);
 	if ((ip->i_flag & IN_MODIFIED) == 0)
 		return (0);
@@ -106,8 +94,8 @@ ext2_update(vp, waitfor)
 		brelse(bp);
 		return (error);
 	}
-	ext2_di2ei( &ip->i_din, (struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE *
-	    ino_to_fsbo(fs, ip->i_number)));
+	ext2_i2ei(ip, (struct ext2_inode *)((char *)bp->b_data +
+	    EXT2_INODE_SIZE * ino_to_fsbo(fs, ip->i_number)));
 /*
 	if (waitfor && (vp->v_mount->mnt_flag & MNT_ASYNC) == 0)
 		return (bwrite(bp));
@@ -166,16 +154,12 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
 		bzero((char *)&oip->i_shortlink, (u_int)oip->i_size);
 		oip->i_size = 0;
 		oip->i_flag |= IN_CHANGE | IN_UPDATE;
-		return (UFS_UPDATE(ovp, 1));
+		return (ext2_update(ovp, 1));
 	}
 	if (oip->i_size == length) {
 		oip->i_flag |= IN_CHANGE | IN_UPDATE;
-		return (UFS_UPDATE(ovp, 0));
+		return (ext2_update(ovp, 0));
 	}
-#if QUOTA
-	if ((error = getinoquota(oip)) != 0)
-		return (error);
-#endif
 	fs = oip->i_e2fs;
 	osize = oip->i_size;
 	ext2_discard_prealloc(oip);
@@ -200,7 +184,7 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
 		else
 			bawrite(bp);
 		oip->i_flag |= IN_CHANGE | IN_UPDATE;
-		return (UFS_UPDATE(ovp, 1));
+		return (ext2_update(ovp, 1));
 	}
 	/*
 	 * Shorten the size of the file. If the file is not being
@@ -256,7 +240,7 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
 	for (i = NDADDR - 1; i > lastblock; i--)
 		oip->i_db[i] = 0;
 	oip->i_flag |= IN_CHANGE | IN_UPDATE;
-	allerror = UFS_UPDATE(ovp, 1);
+	allerror = ext2_update(ovp, 1);
 
 	/*
 	 * Having written the new inode to disk, save its new configuration
@@ -361,9 +345,6 @@ done:
 		oip->i_blocks = 0;
 	oip->i_flag |= IN_CHANGE;
 	vnode_pager_setsize(ovp, length);
-#if QUOTA
-	(void) chkdq(oip, -blocksreleased, NOCRED, 0);
-#endif
 	return (allerror);
 }
 
@@ -488,9 +469,86 @@ int
 ext2_inactive(ap)
         struct vop_inactive_args /* {
 		struct vnode *a_vp;
+		struct thread *a_td;
 	} */ *ap;
 {
-	ext2_discard_prealloc(VTOI(ap->a_vp));
-	return ufs_inactive(ap);
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
+	struct thread *td = ap->a_td;
+	int mode, error = 0;
+
+	ext2_discard_prealloc(ip);
+	if (prtactive && vp->v_usecount != 0)
+		vprint("ext2_inactive: pushing active", vp);
+
+	/*
+	 * Ignore inodes related to stale file handles.
+	 */
+	if (ip->i_mode == 0)
+		goto out;
+	if (ip->i_nlink <= 0) {
+		(void) vn_write_suspend_wait(vp, NULL, V_WAIT);
+		error = ext2_truncate(vp, (off_t)0, 0, NOCRED, td);
+		ip->i_rdev = 0;
+		mode = ip->i_mode;
+		ip->i_mode = 0;
+		ip->i_flag |= IN_CHANGE | IN_UPDATE;
+		ext2_vfree(vp, ip->i_number, mode);
+	}
+	if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) {
+		if ((ip->i_flag & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 &&
+		    vn_write_suspend_wait(vp, NULL, V_NOWAIT)) {
+			ip->i_flag &= ~IN_ACCESS;
+		} else {
+			(void) vn_write_suspend_wait(vp, NULL, V_WAIT);
+			ext2_update(vp, 0);
+		}
+	}
+out:
+	VOP_UNLOCK(vp, 0, td);
+	/*
+	 * If we are done with the inode, reclaim it
+	 * so that it can be reused immediately.
+	 */
+	if (ip->i_mode == 0)
+		vrecycle(vp, NULL, td);
+	return (error);
 }
 
+/*
+ * Reclaim an inode so that it can be used for other purposes.
+ */
+int
+ext2_reclaim(ap)
+	struct vop_reclaim_args /* {
+		struct vnode *a_vp;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct inode *ip;
+	struct vnode *vp = ap->a_vp;
+
+	if (prtactive && vp->v_usecount != 0)
+		vprint("ufs_reclaim: pushing active", vp);
+	ip = VTOI(vp);
+	if (ip->i_flag & IN_LAZYMOD) {
+		ip->i_flag |= IN_MODIFIED;
+		ext2_update(vp, 0);
+	}
+	/*
+	 * Remove the inode from its hash chain.
+	 */
+	ext2_ihashrem(ip);
+	/*
+	 * Purge old data structures associated with the inode.
+	 */
+	cache_purge(vp);
+	if (ip->i_devvp) {
+		vrele(ip->i_devvp);
+		ip->i_devvp = 0;
+	}
+	lockdestroy(&vp->v_lock);
+	FREE(vp->v_data, M_EXT2NODE);
+	vp->v_data = 0;
+	return (0);
+}
diff --git a/sys/gnu/fs/ext2fs/ext2_inode_cnv.c b/sys/gnu/fs/ext2fs/ext2_inode_cnv.c
index 3e8e0ff73445..d64e5498776b 100644
--- a/sys/gnu/fs/ext2fs/ext2_inode_cnv.c
+++ b/sys/gnu/fs/ext2fs/ext2_inode_cnv.c
@@ -23,7 +23,7 @@
  */
 
 /*
- * routines to convert on disk ext2 inodes in dinodes and back
+ * routines to convert on disk ext2 inodes into inodes and back
  */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -31,130 +31,101 @@
 #include <sys/stat.h>
 #include <sys/vnode.h>
 
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-
-/*
- * Undo the definitions in <ufs/ufs/inode.h> that would destroy the include
- * of <gnu/ext2fs/ext2_fs.h>.
- */
-#undef i_atime
-#undef i_blocks
-#undef i_ctime
-#undef i_db
-#undef i_flags
-#undef i_gen
-#undef i_gid
-#undef i_ib
-#undef i_mode
-#undef i_mtime
-#undef i_nlink
-#undef i_rdev
-#undef i_shortlink
-#undef i_size
-#undef i_uid
-
+#include <gnu/ext2fs/inode.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_extern.h>
 
-void
-ext2_print_dinode( di )
-	struct dinode *di;
-{
-	int i;
-	printf( /* "Inode: %5d" */
-		" Type: %10s Mode: 0x%o Flags: 0x%x  Version: %d\n",
-		"n/a", di->di_mode, di->di_flags, di->di_gen);
-	printf( "User: %5lu Group: %5lu  Size: %lu\n",
-		(unsigned long)di->di_uid, (unsigned long)di->di_gid,
-		(unsigned long)di->di_size);
-	printf( "Links: %3d Blockcount: %d\n",
-		di->di_nlink, di->di_blocks);
-	printf( "ctime: 0x%x", di->di_ctime); 
-	printf( "atime: 0x%x", di->di_atime); 
-	printf( "mtime: 0x%x", di->di_mtime); 
-	printf( "BLOCKS: ");
-	for(i=0; i < (di->di_blocks <= 24 ? ((di->di_blocks+1)/2): 12); i++)
-		printf("%d ", di->di_db[i]);
-	printf("\n");
-}
-
 void
 ext2_print_inode( in )
 	struct inode *in;
 {
+	int i;
+
 	printf( "Inode: %5d", in->i_number);
-	ext2_print_dinode(&in->i_din);
+	printf( /* "Inode: %5d" */
+		" Type: %10s Mode: 0x%o Flags: 0x%x  Version: %d\n",
+		"n/a", in->i_mode, in->i_flags, in->i_gen);
+	printf( "User: %5lu Group: %5lu  Size: %lu\n",
+		(unsigned long)in->i_uid, (unsigned long)in->i_gid,
+		(unsigned long)in->i_size);
+	printf( "Links: %3d Blockcount: %d\n",
+		in->i_nlink, in->i_blocks);
+	printf( "ctime: 0x%x", in->i_ctime);
+	printf( "atime: 0x%x", in->i_atime);
+	printf( "mtime: 0x%x", in->i_mtime);
+	printf( "BLOCKS: ");
+	for(i=0; i < (in->i_blocks <= 24 ? ((in->i_blocks+1)/2): 12); i++)
+		printf("%d ", in->i_db[i]);
+	printf("\n");
 }
 
 /*
- *	raw ext2 inode to dinode
+ *	raw ext2 inode to inode
  */
 void
-ext2_ei2di(ei, di)
-        struct ext2_inode *ei;
-        struct dinode *di;
+ext2_ei2i(ei, ip)
+	struct ext2_inode *ei;
+	struct inode *ip;
 {
-        int     i;
+        int i;
 
-        di->di_nlink    = ei->i_links_count;
+	ip->i_nlink = ei->i_links_count;
 	/* Godmar thinks - if the link count is zero, then the inode is
 	   unused - according to ext2 standards. Ufs marks this fact
 	   by setting i_mode to zero - why ?
 	   I can see that this might lead to problems in an undelete.
 	*/
-	di->di_mode     = ei->i_links_count ? ei->i_mode : 0;
-        di->di_size     = ei->i_size;
-        di->di_atime	= ei->i_atime;
-        di->di_mtime	= ei->i_mtime;
-        di->di_ctime	= ei->i_ctime;
-        di->di_flags    = 0;
-        di->di_flags    |= (ei->i_flags & EXT2_APPEND_FL) ? APPEND : 0;
-        di->di_flags    |= (ei->i_flags & EXT2_IMMUTABLE_FL) ? IMMUTABLE : 0;
-        di->di_blocks   = ei->i_blocks;
-        di->di_gen      = ei->i_generation;
-        di->di_uid      = ei->i_uid;
-        di->di_gid      = ei->i_gid;
+	ip->i_mode = ei->i_links_count ? ei->i_mode : 0;
+	ip->i_size = ei->i_size;
+	ip->i_atime = ei->i_atime;
+	ip->i_mtime = ei->i_mtime;
+	ip->i_ctime = ei->i_ctime;
+	ip->i_flags = 0;
+	ip->i_flags |= (ei->i_flags & EXT2_APPEND_FL) ? APPEND : 0;
+	ip->i_flags |= (ei->i_flags & EXT2_IMMUTABLE_FL) ? IMMUTABLE : 0;
+	ip->i_blocks = ei->i_blocks;
+	ip->i_gen = ei->i_generation;
+	ip->i_uid = ei->i_uid;
+	ip->i_gid = ei->i_gid;
 	/* XXX use memcpy */
-        for(i = 0; i < NDADDR; i++)
-                di->di_db[i] = ei->i_block[i];
-        for(i = 0; i < NIADDR; i++)
-                di->di_ib[i] = ei->i_block[EXT2_NDIR_BLOCKS + i];
+	for(i = 0; i < NDADDR; i++)
+		ip->i_db[i] = ei->i_block[i];
+	for(i = 0; i < NIADDR; i++)
+		ip->i_ib[i] = ei->i_block[EXT2_NDIR_BLOCKS + i];
 }
 
 /*
- *	dinode to raw ext2 inode
+ *	inode to raw ext2 inode
  */
 void
-ext2_di2ei(di, ei)
-        struct dinode *di;
-        struct ext2_inode *ei;
+ext2_i2ei(ip, ei)
+	struct inode *ip;
+	struct ext2_inode *ei;
 {
-        int     i;
+	int i;
 
-        ei->i_mode              = di->di_mode;
-        ei->i_links_count       = di->di_nlink;
+	ei->i_mode = ip->i_mode;
+        ei->i_links_count = ip->i_nlink;
 	/* 
 	   Godmar thinks: if dtime is nonzero, ext2 says this inode
 	   has been deleted, this would correspond to a zero link count
 	 */
-        ei->i_dtime             = ei->i_links_count ? 0 : di->di_mtime;
-        ei->i_size              = di->di_size;
-        ei->i_atime             = di->di_atime;
-        ei->i_mtime             = di->di_mtime;
-        ei->i_ctime             = di->di_ctime;
-        ei->i_flags             = di->di_flags;
-        ei->i_flags    		= 0;
-        ei->i_flags    		|= (di->di_flags & APPEND) ? EXT2_APPEND_FL: 0;
-        ei->i_flags    		|= (di->di_flags & IMMUTABLE) 
-							? EXT2_IMMUTABLE_FL: 0;
-        ei->i_blocks            = di->di_blocks;
-        ei->i_generation        = di->di_gen;
-        ei->i_uid               = di->di_uid;
-        ei->i_gid               = di->di_gid;
+	ei->i_dtime = ei->i_links_count ? 0 : ip->i_mtime;
+	ei->i_size = ip->i_size;
+	ei->i_atime = ip->i_atime;
+	ei->i_mtime = ip->i_mtime;
+	ei->i_ctime = ip->i_ctime;
+	ei->i_flags = ip->i_flags;
+	ei->i_flags = 0;
+	ei->i_flags |= (ip->i_flags & APPEND) ? EXT2_APPEND_FL: 0;
+	ei->i_flags |= (ip->i_flags & IMMUTABLE) ? EXT2_IMMUTABLE_FL: 0;
+	ei->i_blocks = ip->i_blocks;
+	ei->i_generation = ip->i_gen;
+	ei->i_uid = ip->i_uid;
+	ei->i_gid = ip->i_gid;
 	/* XXX use memcpy */
-        for(i = 0; i < NDADDR; i++)
-                ei->i_block[i] = di->di_db[i];
-        for(i = 0; i < NIADDR; i++)
-                ei->i_block[EXT2_NDIR_BLOCKS + i] = di->di_ib[i];
+	for(i = 0; i < NDADDR; i++)
+		ei->i_block[i] = ip->i_db[i];
+	for(i = 0; i < NIADDR; i++)
+		ei->i_block[EXT2_NDIR_BLOCKS + i] = ip->i_ib[i];
 }
diff --git a/sys/gnu/fs/ext2fs/ext2_linux_balloc.c b/sys/gnu/fs/ext2fs/ext2_linux_balloc.c
index fc723114dfa6..632044009643 100644
--- a/sys/gnu/fs/ext2fs/ext2_linux_balloc.c
+++ b/sys/gnu/fs/ext2fs/ext2_linux_balloc.c
@@ -35,9 +35,8 @@
 #include <sys/mount.h>
 #include <sys/vnode.h>
 
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/ufsmount.h>
+#include <gnu/ext2fs/inode.h>
+#include <gnu/ext2fs/ext2_mount.h>
 #include <gnu/ext2fs/ext2_extern.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
@@ -61,13 +60,13 @@ static void read_block_bitmap (struct mount * mp,
 			       unsigned int block_group,
 			       unsigned long bitmap_nr)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	struct ext2_group_desc * gdp;
 	struct buffer_head * bh;
 	int    error;
 	
 	gdp = get_group_desc (mp, block_group, NULL);
-	if ((error = bread (VFSTOUFS(mp)->um_devvp, 
+	if ((error = bread (VFSTOEXT2(mp)->um_devvp,
 		fsbtodb(sb, gdp->bg_block_bitmap),sb->s_blocksize, NOCRED, &bh)) != 0)
 		panic ( "read_block_bitmap: "
 			    "Cannot read block bitmap - "
@@ -93,7 +92,7 @@ static int load__block_bitmap (struct mount * mp,
 			       unsigned int block_group)
 {
 	int i, j;
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	unsigned long block_bitmap_number;
 	struct buffer_head * block_bitmap;
 
@@ -152,7 +151,7 @@ static int load__block_bitmap (struct mount * mp,
 static __inline int load_block_bitmap (struct mount * mp,
 				       unsigned int block_group)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	if (sb->s_loaded_block_bitmaps > 0 &&
 	    sb->s_block_bitmap_number[0] == block_group)
 		return 0;
@@ -168,7 +167,7 @@ static __inline int load_block_bitmap (struct mount * mp,
 void ext2_free_blocks (struct mount * mp, unsigned long block,
 		       unsigned long count)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	struct buffer_head * bh;
 	struct buffer_head * bh2;
 	unsigned long block_group;
@@ -182,13 +181,13 @@ void ext2_free_blocks (struct mount * mp, unsigned long block,
 		printf ("ext2_free_blocks: nonexistent device");
 		return;
 	}
-	lock_super (VFSTOUFS(mp)->um_devvp);
+	lock_super (VFSTOEXT2(mp)->um_devvp);
 	if (block < es->s_first_data_block || 
 	    (block + count) > es->s_blocks_count) {
 		printf ( "ext2_free_blocks: "
 			    "Freeing blocks not in datazone - "
 			    "block = %lu, count = %lu", block, count);
-		unlock_super (VFSTOUFS(mp)->um_devvp);
+		unlock_super (VFSTOEXT2(mp)->um_devvp);
 		return;
 	}
 
@@ -238,7 +237,7 @@ void ext2_free_blocks (struct mount * mp, unsigned long block,
 	}
 ****/
 	sb->s_dirt = 1;
-	unlock_super (VFSTOUFS(mp)->um_devvp);
+	unlock_super (VFSTOEXT2(mp)->um_devvp);
 	return;
 }
 
@@ -253,7 +252,7 @@ int ext2_new_block (struct mount * mp, unsigned long goal,
 		    u_int32_t * prealloc_count,
 		    u_int32_t * prealloc_block)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	struct buffer_head * bh;
 	struct buffer_head * bh2;
 	char * p, * r;
@@ -269,7 +268,7 @@ int ext2_new_block (struct mount * mp, unsigned long goal,
 		printf ("ext2_new_block: nonexistent device");
 		return 0;
 	}
-	lock_super (VFSTOUFS(mp)->um_devvp);
+	lock_super (VFSTOEXT2(mp)->um_devvp);
 
         ext2_debug ("goal=%lu.\n", goal);
 
@@ -356,7 +355,7 @@ repeat:
 			break;
 	}
 	if (k >= sb->s_groups_count) {
-		unlock_super (VFSTOUFS(mp)->um_devvp);
+		unlock_super (VFSTOEXT2(mp)->um_devvp);
 		return 0;
 	}
 	bitmap_nr = load_block_bitmap (mp, i);
@@ -372,7 +371,7 @@ repeat:
 	if (j >= EXT2_BLOCKS_PER_GROUP(sb)) {
 		printf ( "ext2_new_block: "
 			 "Free blocks count corrupted for block group %d", i);
-		unlock_super (VFSTOUFS(mp)->um_devvp);
+		unlock_super (VFSTOEXT2(mp)->um_devvp);
 		return 0;
 	}
 
@@ -439,7 +438,7 @@ got_block:
 		printf ( "ext2_new_block: "
 			    "block >= blocks count - "
 			    "block_group = %d, block=%d", i, j);
-		unlock_super (VFSTOUFS(mp)->um_devvp);
+		unlock_super (VFSTOEXT2(mp)->um_devvp);
 		return 0;
 	}
 
@@ -450,14 +449,14 @@ got_block:
 	mark_buffer_dirty(bh2);
 	es->s_free_blocks_count--;
 	sb->s_dirt = 1;
-	unlock_super (VFSTOUFS(mp)->um_devvp);
+	unlock_super (VFSTOEXT2(mp)->um_devvp);
 	return j;
 }
 
 #ifdef unused
 static unsigned long ext2_count_free_blocks (struct mount * mp)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 #ifdef EXT2FS_DEBUG
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x;
@@ -465,7 +464,7 @@ static unsigned long ext2_count_free_blocks (struct mount * mp)
 	struct ext2_group_desc * gdp;
 	int i;
 	
-	lock_super (VFSTOUFS(mp)->um_devvp);
+	lock_super (VFSTOEXT2(mp)->um_devvp);
 	es = sb->s_es;
 	desc_count = 0;
 	bitmap_count = 0;
@@ -482,7 +481,7 @@ static unsigned long ext2_count_free_blocks (struct mount * mp)
 	}
 	ext2_debug( "stored = %lu, computed = %lu, %lu\n",
 	       es->s_free_blocks_count, desc_count, bitmap_count);
-	unlock_super (VFSTOUFS(mp)->um_devvp);
+	unlock_super (VFSTOEXT2(mp)->um_devvp);
 	return bitmap_count;
 #else
 	return sb->s_es->s_free_blocks_count;
@@ -520,7 +519,7 @@ int ext2_group_sparse(int group)
 #ifdef unused
 static void ext2_check_blocks_bitmap (struct mount * mp)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	struct buffer_head * bh;
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x;
@@ -529,7 +528,7 @@ static void ext2_check_blocks_bitmap (struct mount * mp)
 	struct ext2_group_desc * gdp;
 	int i, j;
 
-	lock_super (VFSTOUFS(mp)->um_devvp);
+	lock_super (VFSTOEXT2(mp)->um_devvp);
 	es = sb->s_es;
 	desc_count = 0;
 	bitmap_count = 0;
@@ -586,7 +585,7 @@ static void ext2_check_blocks_bitmap (struct mount * mp)
 			    "Wrong free blocks count in super block, "
 			    "stored = %lu, counted = %lu",
 			    (unsigned long) es->s_free_blocks_count, bitmap_count);
-	unlock_super (VFSTOUFS(mp)->um_devvp);
+	unlock_super (VFSTOEXT2(mp)->um_devvp);
 }
 #endif /* unused */
 
diff --git a/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c b/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c
index 01ae55b078dc..64d96b21104c 100644
--- a/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c
+++ b/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c
@@ -36,10 +36,8 @@
 #include <sys/mount.h>
 #include <sys/vnode.h>
 
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-#include <ufs/ufs/ufsmount.h>
+#include <gnu/ext2fs/inode.h>
+#include <gnu/ext2fs/ext2_mount.h>
 #include <gnu/ext2fs/ext2_extern.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
@@ -69,7 +67,7 @@ struct ext2_group_desc * get_group_desc (struct mount * mp,
 						unsigned int block_group,
 						struct buffer_head ** bh)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	unsigned long group_desc;
 	unsigned long desc;
 	struct ext2_group_desc * gdp;
@@ -98,13 +96,13 @@ static void read_inode_bitmap (struct mount * mp,
 			       unsigned long block_group,
 			       unsigned int bitmap_nr)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	struct ext2_group_desc * gdp;
 	struct buffer_head * bh;
 	int	error;
 
 	gdp = get_group_desc (mp, block_group, NULL);
-	if ((error = bread (VFSTOUFS(mp)->um_devvp, 
+	if ((error = bread (VFSTOEXT2(mp)->um_devvp,
 			    fsbtodb(sb, gdp->bg_inode_bitmap), 
 			    sb->s_blocksize,
 			    NOCRED, &bh)) != 0)
@@ -131,7 +129,7 @@ static void read_inode_bitmap (struct mount * mp,
 static int load_inode_bitmap (struct mount * mp,
 			      unsigned int block_group)
 {
-	struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+	struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	int i, j;
 	unsigned long inode_bitmap_number;
 	struct buffer_head * inode_bitmap;
@@ -447,14 +445,14 @@ repeat:
 static unsigned long ext2_count_free_inodes (struct mount * mp)
 {
 #ifdef EXT2FS_DEBUG
-        struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs;
+        struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs;
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x;
 	int bitmap_nr;
 	struct ext2_group_desc * gdp;
 	int i;
 
-	lock_super (VFSTOUFS(mp)->um_devvp);
+	lock_super (VFSTOEXT2(mp)->um_devvp);
 	es = sb->s_es;
 	desc_count = 0;
 	bitmap_count = 0;
@@ -471,10 +469,10 @@ static unsigned long ext2_count_free_inodes (struct mount * mp)
 	}
 	ext2_debug("stored = %lu, computed = %lu, %lu\n",
 		es->s_free_inodes_count, desc_count, bitmap_count);
-	unlock_super (VFSTOUFS(mp)->um_devvp);
+	unlock_super (VFSTOEXT2(mp)->um_devvp);
 	return desc_count;
 #else
-	return VFSTOUFS(mp)->um_e2fsb->s_free_inodes_count;
+	return VFSTOEXT2(mp)->um_e2fsb->s_free_inodes_count;
 #endif
 }
 #endif /* unused */
diff --git a/sys/gnu/fs/ext2fs/ext2_lookup.c b/sys/gnu/fs/ext2fs/ext2_lookup.c
index 2c1de41414f4..14b78b58a7cf 100644
--- a/sys/gnu/fs/ext2fs/ext2_lookup.c
+++ b/sys/gnu/fs/ext2fs/ext2_lookup.c
@@ -55,13 +55,10 @@
 #include <sys/malloc.h>
 #include <sys/dirent.h>
 
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
 #include <ufs/ufs/dir.h>
-#include <ufs/ufs/ufsmount.h>
-#include <ufs/ufs/ufs_extern.h>
 
+#include <gnu/ext2fs/inode.h>
+#include <gnu/ext2fs/ext2_mount.h>
 #include <gnu/ext2fs/ext2_extern.h>
 #include <gnu/ext2fs/ext2_fs.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
@@ -364,7 +361,7 @@ ext2_lookup(ap)
 	 * profiling time and hence has been removed in the interest
 	 * of simplicity.
 	 */
-	bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
+	bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
 	if (nameiop != LOOKUP || dp->i_diroff == 0 ||
 	    dp->i_diroff > dp->i_size) {
 		entryoffsetinblock = 0;
@@ -373,7 +370,8 @@ ext2_lookup(ap)
 	} else {
 		dp->i_offset = dp->i_diroff;
 		if ((entryoffsetinblock = dp->i_offset & bmask) &&
-		    (error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)))
+		    (error = ext2_blkatoff(vdp, (off_t)dp->i_offset, NULL,
+		    &bp)))
 			return (error);
 		numdirpasses = 2;
 		nchstats.ncs_2passes++;
@@ -391,7 +389,8 @@ searchloop:
 			if (bp != NULL)
 				brelse(bp);
 			if ((error =
-			    UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)) != 0)
+			    ext2_blkatoff(vdp, (off_t)dp->i_offset, NULL,
+			    &bp)) != 0)
 				return (error);
 			entryoffsetinblock = 0;
 		}
@@ -416,7 +415,7 @@ searchloop:
 		if (ep->rec_len == 0 ||
 		    (dirchk && ext2_dirbadentry(vdp, ep, entryoffsetinblock))) {
 			int i;
-			ufs_dirbad(dp, dp->i_offset, "mangled entry");
+			ext2_dirbad(dp, dp->i_offset, "mangled entry");
 			i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
 			dp->i_offset += i;
 			entryoffsetinblock += i;
@@ -558,7 +557,7 @@ found:
 	 */
 	if (entryoffsetinblock + EXT2_DIR_REC_LEN(ep->name_len)
 		> dp->i_size) {
-		ufs_dirbad(dp, dp->i_offset, "i_size too small");
+		ext2_dirbad(dp, dp->i_offset, "i_size too small");
 		dp->i_size = entryoffsetinblock+EXT2_DIR_REC_LEN(ep->name_len);
 		dp->i_flag |= IN_CHANGE | IN_UPDATE;
 	}
@@ -700,6 +699,21 @@ found:
 	return (0);
 }
 
+void
+ext2_dirbad(ip, offset, how)
+	struct inode *ip;
+	doff_t offset;
+	char *how;
+{
+	struct mount *mp;
+
+	mp = ITOV(ip)->v_mount;
+	(void)printf("%s: bad dir ino %lu at offset %ld: %s\n",
+	    mp->mnt_stat.f_mntonname, (u_long)ip->i_number, (long)offset, how);
+	if ((mp->mnt_flag & MNT_RDONLY) == 0)
+		panic("ext2_dirbad: bad dir");
+}
+
 /*
  * Do consistency checking on a directory entry:
  *	record length must be multiple of 4
@@ -804,7 +818,7 @@ ext2_direnter(ip, dvp, cnp)
 		auio.uio_td = (struct thread *)0;
 		error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
 		if (DIRBLKSIZ >
-		    VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
+		    VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
 			/* XXX should grow with balloc() */
 			panic("ext2_direnter: frag size");
 		else if (!error) {
@@ -835,7 +849,8 @@ ext2_direnter(ip, dvp, cnp)
 	/*
 	 * Get the block containing the space for the new directory entry.
 	 */
-	if ((error = UFS_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp)) != 0)
+	if ((error = ext2_blkatoff(dvp, (off_t)dp->i_offset, &dirbuf,
+	    &bp)) != 0)
 		return (error);
 	/*
 	 * Find space for the new entry. In the simple case, the entry at
@@ -881,7 +896,7 @@ ext2_direnter(ip, dvp, cnp)
 	error = BUF_WRITE(bp);
 	dp->i_flag |= IN_CHANGE | IN_UPDATE;
 	if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
-		error = UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC,
+		error = ext2_truncate(dvp, (off_t)dp->i_endoff, IO_SYNC,
 		    cnp->cn_cred, cnp->cn_thread);
 	return (error);
 }
@@ -914,7 +929,8 @@ ext2_dirremove(dvp, cnp)
 		 * First entry in block: set d_ino to zero.
 		 */
 		if ((error =
-		    UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
+		    ext2_blkatoff(dvp, (off_t)dp->i_offset, (char **)&ep,
+		    &bp)) != 0)
 			return (error);
 		ep->inode = 0;
 		error = BUF_WRITE(bp);
@@ -924,7 +940,7 @@ ext2_dirremove(dvp, cnp)
 	/*
 	 * Collapse new free space into previous entry.
 	 */
-	if ((error = UFS_BLKATOFF(dvp, (off_t)(dp->i_offset - dp->i_count),
+	if ((error = ext2_blkatoff(dvp, (off_t)(dp->i_offset - dp->i_count),
 	    (char **)&ep, &bp)) != 0)
 		return (error);
 	ep->rec_len += dp->i_reclen;
@@ -948,7 +964,8 @@ ext2_dirrewrite(dp, ip, cnp)
 	struct vnode *vdp = ITOV(dp);
 	int error;
 
-	if ((error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
+	if ((error = ext2_blkatoff(vdp, (off_t)dp->i_offset, (char **)&ep,
+	    &bp)) != 0)
 		return (error);
 	ep->inode = ip->i_number;
 	if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
diff --git a/sys/gnu/fs/ext2fs/ext2_readwrite.c b/sys/gnu/fs/ext2fs/ext2_readwrite.c
index 2772f7b2306e..73f900cd3230 100644
--- a/sys/gnu/fs/ext2fs/ext2_readwrite.c
+++ b/sys/gnu/fs/ext2fs/ext2_readwrite.c
@@ -301,12 +301,12 @@ WRITE(ap)
 		ip->i_mode &= ~(ISUID | ISGID);
 	if (error) {
 		if (ioflag & IO_UNIT) {
-			(void)UFS_TRUNCATE(vp, osize,
+			(void)ext2_truncate(vp, osize,
 			    ioflag & IO_SYNC, ap->a_cred, uio->uio_td);
 			uio->uio_offset -= resid - uio->uio_resid;
 			uio->uio_resid = resid;
 		}
 	} else if (resid > uio->uio_resid && (ioflag & IO_SYNC))
-		error = UFS_UPDATE(vp, 1);
+		error = ext2_update(vp, 1);
 	return (error);
 }
diff --git a/sys/gnu/fs/ext2fs/ext2_subr.c b/sys/gnu/fs/ext2fs/ext2_subr.c
index 69eecf1e236b..587ed0520f6d 100644
--- a/sys/gnu/fs/ext2fs/ext2_subr.c
+++ b/sys/gnu/fs/ext2fs/ext2_subr.c
@@ -50,9 +50,7 @@
 #include <sys/ucred.h>
 #include <sys/vnode.h>
 
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-
+#include <gnu/ext2fs/inode.h>
 #include <gnu/ext2fs/ext2_extern.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
 #include <gnu/ext2fs/fs.h>
@@ -121,7 +119,7 @@ ext2_checkoverlap(bp, ip)
 			continue;
 		vprint("Disk overlap", vp);
 		(void)printf("\tstart %d, end %d overlap start %lld, end %ld\n",
-			start, last, ep->b_blkno,
+			start, last, (long long)ep->b_blkno,
 			(long)(ep->b_blkno + btodb(ep->b_bcount) - 1));
 		panic("Disk buffer overlap");
 	}
diff --git a/sys/gnu/fs/ext2fs/ext2_vfsops.c b/sys/gnu/fs/ext2fs/ext2_vfsops.c
index 54c43058cb3d..b9afe91a1f7f 100644
--- a/sys/gnu/fs/ext2fs/ext2_vfsops.c
+++ b/sys/gnu/fs/ext2fs/ext2_vfsops.c
@@ -40,8 +40,6 @@
  * $FreeBSD$
  */
 
-#include "opt_quota.h"
-
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/namei.h>
@@ -57,12 +55,8 @@
 #include <sys/stat.h>
 #include <sys/mutex.h>
 
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/ufsmount.h>
-#include <ufs/ufs/inode.h>
-#include <ufs/ufs/ufs_extern.h>
-
+#include <gnu/ext2fs/ext2_mount.h>
+#include <gnu/ext2fs/inode.h>
 
 #include <gnu/ext2fs/fs.h>
 #include <gnu/ext2fs/ext2_extern.h>
@@ -71,26 +65,29 @@
 
 static int ext2_fhtovp(struct mount *, struct fid *, struct vnode **);
 static int ext2_flushfiles(struct mount *mp, int flags, struct thread *td);
+static int ext2_init(struct vfsconf *);
 static int ext2_mount(struct mount *,
 	    char *, caddr_t, struct nameidata *, struct thread *);
 static int ext2_mountfs(struct vnode *, struct mount *, struct thread *);
 static int ext2_reload(struct mount *mountp, struct ucred *cred,
 			struct thread *td);
-static int ext2_sbupdate(struct ufsmount *, int);
+static int ext2_root(struct mount *, struct vnode **vpp);
+static int ext2_sbupdate(struct ext2mount *, int);
 static int ext2_statfs(struct mount *, struct statfs *, struct thread *);
 static int ext2_sync(struct mount *, int, struct ucred *, struct thread *);
 static int ext2_unmount(struct mount *, int, struct thread *);
 static int ext2_vget(struct mount *, ino_t, int, struct vnode **);
 static int ext2_vptofh(struct vnode *, struct fid *);
 
-static MALLOC_DEFINE(M_EXT2NODE, "EXT2 node", "EXT2 vnode private part");
+MALLOC_DEFINE(M_EXT2NODE, "EXT2 node", "EXT2 vnode private part");
+static MALLOC_DEFINE(M_EXT2MNT, "EXT2 mount", "EXT2 mount structure");
 
 static struct vfsops ext2fs_vfsops = {
 	ext2_mount,
-	ufs_start,		/* empty function */
+	vfs_stdstart,
 	ext2_unmount,
-	ufs_root,		/* root inode via vget */
-	ufs_quotactl,		/* does operations associated with quotas */
+	ext2_root,		/* root inode via vget */
+	vfs_stdquotactl,
 	ext2_statfs,
 	ext2_sync,
 	ext2_vget,
@@ -129,7 +126,7 @@ ext2_mountroot()
 	register struct ext2_sb_info *fs;
 	register struct mount *mp;
 	struct thread *td = curthread;
-	struct ufsmount *ump;
+	struct ext2mount *ump;
 	u_int size;
 	int error;
 	
@@ -155,7 +152,7 @@ ext2_mountroot()
 	TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list);
 	mp->mnt_flag |= MNT_ROOTFS;
 	mp->mnt_vnodecovered = NULLVP;
-	ump = VFSTOUFS(mp);
+	ump = VFSTOEXT2(mp);
 	fs = ump->um_e2fs;
 	bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
 	fs->fs_fsmnt[0] = '/';
@@ -180,13 +177,13 @@ static int
 ext2_mount(mp, path, data, ndp, td)
 	register struct mount *mp;	
 	char *path;
-	caddr_t data;		/* this is actually a (struct ufs_args *) */
+	caddr_t data;		/* this is actually a (struct ext2_args *) */
 	struct nameidata *ndp;
 	struct thread *td;
 {
 	struct vnode *devvp;
-	struct ufs_args args;
-	struct ufsmount *ump = 0;
+	struct ext2_args args;
+	struct ext2mount *ump = 0;
 	register struct ext2_sb_info *fs;
 	size_t size;
 	int error, flags;
@@ -195,7 +192,7 @@ ext2_mount(mp, path, data, ndp, td)
 	/* Double-check the length of path.. */
 	if (strlen(path) >= MAXMNTLEN - 1)
 		return (ENAMETOOLONG);
-	error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args));
+	error = copyin(data, (caddr_t)&args, sizeof (struct ext2_args));
 	if (error != 0)
 		return (error);
 	/*
@@ -203,7 +200,7 @@ ext2_mount(mp, path, data, ndp, td)
 	 * read/write; if there is no device name, that's all we do.
 	 */
 	if (mp->mnt_flag & MNT_UPDATE) {
-		ump = VFSTOUFS(mp);
+		ump = VFSTOEXT2(mp);
 		fs = ump->um_e2fs;
 		error = 0;
 		if (fs->s_rd_only == 0 && (mp->mnt_flag & MNT_RDONLY)) {
@@ -310,7 +307,7 @@ ext2_mount(mp, path, data, ndp, td)
 		vrele(devvp);
 		return (error);
 	}
-	ump = VFSTOUFS(mp);
+	ump = VFSTOEXT2(mp);
 	fs = ump->um_e2fs;
 	/*
 	 * Note that this strncpy() is ok because of a check at the start
@@ -466,7 +463,7 @@ static int compute_sb_data(devvp, es, fs)
     V(s_db_per_group)
 
     fs->s_group_desc = bsd_malloc(db_count * sizeof (struct buf *),
-		M_UFSMNT, M_WAITOK);
+		M_EXT2MNT, M_WAITOK);
 
     /* adjust logic_sb_block */
     if(fs->s_blocksize > SBSIZE) 
@@ -481,7 +478,7 @@ static int compute_sb_data(devvp, es, fs)
 	if(error) {
 	    for (j = 0; j < i; j++)
 		brelse(fs->s_group_desc[j]);
-	    bsd_free(fs->s_group_desc, M_UFSMNT);
+	    bsd_free(fs->s_group_desc, M_EXT2MNT);
 	    printf("EXT2-fs: unable to read group descriptors (%d)\n", error);
 	    return EIO;
 	}
@@ -491,7 +488,7 @@ static int compute_sb_data(devvp, es, fs)
     if(!ext2_check_descriptors(fs)) {
 	    for (j = 0; j < db_count; j++)
 		    ULCK_BUF(fs->s_group_desc[j])
-	    bsd_free(fs->s_group_desc, M_UFSMNT);
+	    bsd_free(fs->s_group_desc, M_EXT2MNT);
 	    printf("EXT2-fs: (ext2_check_descriptors failure) "
 		   "unable to read group descriptors\n");
 	    return EIO;
@@ -539,7 +536,7 @@ ext2_reload(mountp, cred, td)
 	/*
 	 * Step 1: invalidate all cached meta-data.
 	 */
-	devvp = VFSTOUFS(mountp)->um_devvp;
+	devvp = VFSTOEXT2(mountp)->um_devvp;
 	if (vinvalbuf(devvp, 0, cred, td, 0, 0))
 		panic("ext2_reload: dirty1");
 	/*
@@ -553,7 +550,7 @@ ext2_reload(mountp, cred, td)
 		brelse(bp);
 		return (EIO);		/* XXX needs translation */
 	}
-	fs = VFSTOUFS(mountp)->um_e2fs;
+	fs = VFSTOEXT2(mountp)->um_e2fs;
 	bcopy(bp->b_data, fs->s_es, sizeof(struct ext2_super_block));
 
 	if((error = compute_sb_data(devvp, es, fs)) != 0) {
@@ -600,9 +597,8 @@ loop:
 			vput(vp);
 			return (error);
 		}
-		ext2_ei2di((struct ext2_inode *) ((char *)bp->b_data + 
-		    EXT2_INODE_SIZE * ino_to_fsbo(fs, ip->i_number)), 
-		    &ip->i_din);
+		ext2_ei2i((struct ext2_inode *) ((char *)bp->b_data +
+		    EXT2_INODE_SIZE * ino_to_fsbo(fs, ip->i_number)), ip);
 		brelse(bp);
 		vput(vp);
 		mtx_lock(&mntvnode_mtx);
@@ -620,12 +616,12 @@ ext2_mountfs(devvp, mp, td)
 	struct mount *mp;
 	struct thread *td;
 {
-	register struct ufsmount *ump;
+	register struct ext2mount *ump;
 	struct buf *bp;
 	register struct ext2_sb_info *fs;
 	struct ext2_super_block * es;
 	dev_t dev = devvp->v_rdev;
-	int error, i;
+	int error;
 	int ronly;
 
 	/*
@@ -677,22 +673,16 @@ ext2_mountfs(devvp, mp, td)
 			goto out;
 		}
 	}
-	ump = bsd_malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
+	ump = bsd_malloc(sizeof *ump, M_EXT2MNT, M_WAITOK);
 	bzero((caddr_t)ump, sizeof *ump);
-	ump->um_malloctype = M_EXT2NODE;
-	ump->um_blkatoff = ext2_blkatoff;
-	ump->um_truncate = ext2_truncate;
-	ump->um_update = ext2_update;
-	ump->um_valloc = ext2_valloc;
-	ump->um_vfree = ext2_vfree;
 	/* I don't know whether this is the right strategy. Note that
 	   we dynamically allocate both a ext2_sb_info and a ext2_super_block
 	   while Linux keeps the super block in a locked buffer
 	 */
 	ump->um_e2fs = bsd_malloc(sizeof(struct ext2_sb_info), 
-		M_UFSMNT, M_WAITOK);
+		M_EXT2MNT, M_WAITOK);
 	ump->um_e2fs->s_es = bsd_malloc(sizeof(struct ext2_super_block), 
-		M_UFSMNT, M_WAITOK);
+		M_EXT2MNT, M_WAITOK);
 	bcopy(es, ump->um_e2fs->s_es, (u_int)sizeof(struct ext2_super_block));
 	if ((error = compute_sb_data(devvp, ump->um_e2fs->s_es, ump->um_e2fs)))
 		goto out;
@@ -720,14 +710,12 @@ ext2_mountfs(devvp, mp, td)
 	ump->um_mountp = mp;
 	ump->um_dev = dev;
 	ump->um_devvp = devvp;
-	/* setting those two parameters allows us to use 
+	/* setting those two parameters allowed us to use
 	   ufs_bmap w/o changse !
 	*/
 	ump->um_nindir = EXT2_ADDR_PER_BLOCK(fs);
 	ump->um_bptrtodb = fs->s_es->s_log_block_size + 1;
 	ump->um_seqinc = EXT2_FRAGS_PER_BLOCK(fs);
-	for (i = 0; i < MAXQUOTAS; i++)
-		ump->um_quotas[i] = NULLVP; 
 	devvp->v_rdev->si_mountpoint = mp;
 	if (ronly == 0) 
 		ext2_sbupdate(ump, MNT_WAIT);
@@ -737,9 +725,9 @@ out:
 		brelse(bp);
 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, td);
 	if (ump) {
-		bsd_free(ump->um_e2fs->s_es, M_UFSMNT);
-		bsd_free(ump->um_e2fs, M_UFSMNT);
-		bsd_free(ump, M_UFSMNT);
+		bsd_free(ump->um_e2fs->s_es, M_EXT2MNT);
+		bsd_free(ump->um_e2fs, M_EXT2MNT);
+		bsd_free(ump, M_EXT2MNT);
 		mp->mnt_data = (qaddr_t)0;
 	}
 	return (error);
@@ -754,7 +742,7 @@ ext2_unmount(mp, mntflags, td)
 	int mntflags;
 	struct thread *td;
 {
-	register struct ufsmount *ump;
+	register struct ext2mount *ump;
 	register struct ext2_sb_info *fs;
 	int error, flags, ronly, i;
 
@@ -766,7 +754,7 @@ ext2_unmount(mp, mntflags, td)
 	}
 	if ((error = ext2_flushfiles(mp, flags, td)) != 0)
 		return (error);
-	ump = VFSTOUFS(mp);
+	ump = VFSTOEXT2(mp);
 	fs = ump->um_e2fs;
 	ronly = fs->s_rd_only;
 	if (ronly == 0) {
@@ -778,7 +766,7 @@ ext2_unmount(mp, mntflags, td)
 	/* release buffers containing group descriptors */
 	for(i = 0; i < fs->s_db_per_group; i++) 
 		ULCK_BUF(fs->s_group_desc[i])
-	bsd_free(fs->s_group_desc, M_UFSMNT);
+	bsd_free(fs->s_group_desc, M_EXT2MNT);
 
 	/* release cached inode/block bitmaps */
         for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++)
@@ -793,9 +781,9 @@ ext2_unmount(mp, mntflags, td)
 	error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE,
 		NOCRED, td);
 	vrele(ump->um_devvp);
-	bsd_free(fs->s_es, M_UFSMNT);
-	bsd_free(fs, M_UFSMNT);
-	bsd_free(ump, M_UFSMNT);
+	bsd_free(fs->s_es, M_EXT2MNT);
+	bsd_free(fs, M_EXT2MNT);
+	bsd_free(ump, M_EXT2MNT);
 	mp->mnt_data = (qaddr_t)0;
 	mp->mnt_flag &= ~MNT_LOCAL;
 	return (error);
@@ -810,28 +798,8 @@ ext2_flushfiles(mp, flags, td)
 	int flags;
 	struct thread *td;
 {
-	register struct ufsmount *ump;
 	int error;
-#if QUOTA
-	int i;
-#endif
 
-	ump = VFSTOUFS(mp);
-#if QUOTA
-	if (mp->mnt_flag & MNT_QUOTA) {
-		if ((error = vflush(mp, 0, SKIPSYSTEM|flags)) != 0)
-			return (error);
-		for (i = 0; i < MAXQUOTAS; i++) {
-			if (ump->um_quotas[i] == NULLVP)
-				continue;
-			quotaoff(td, mp, i);
-		}
-		/*
-		 * Here we fall through to vflush again to ensure
-		 * that we have gotten rid of all the system vnodes.
-		 */
-	}
-#endif
 	error = vflush(mp, 0, flags);
 	return (error);
 }
@@ -847,12 +815,12 @@ ext2_statfs(mp, sbp, td)
 	struct thread *td;
 {
         unsigned long overhead;
-	register struct ufsmount *ump;
+	register struct ext2mount *ump;
 	register struct ext2_sb_info *fs;
 	register struct ext2_super_block *es;
 	int i, nsb;
 
-	ump = VFSTOUFS(mp);
+	ump = VFSTOEXT2(mp);
 	fs = ump->um_e2fs;
 	es = fs->s_es;
 
@@ -908,7 +876,7 @@ ext2_sync(mp, waitfor, cred, td)
 {
 	struct vnode *nvp, *vp;
 	struct inode *ip;
-	struct ufsmount *ump = VFSTOUFS(mp);
+	struct ext2mount *ump = VFSTOEXT2(mp);
 	struct ext2_sb_info *fs;
 	int error, allerror = 0;
 
@@ -964,9 +932,6 @@ loop:
 			allerror = error;
 		VOP_UNLOCK(ump->um_devvp, 0, td);
 	}
-#if QUOTA
-	qsync(mp);
-#endif
 	/*
 	 * Write back modified superblock.
 	 */
@@ -994,17 +959,17 @@ ext2_vget(mp, ino, flags, vpp)
 {
 	register struct ext2_sb_info *fs;
 	register struct inode *ip;
-	struct ufsmount *ump;
+	struct ext2mount *ump;
 	struct buf *bp;
 	struct vnode *vp;
 	dev_t dev;
 	int i, error;
 	int used_blocks;
 
-	ump = VFSTOUFS(mp);
+	ump = VFSTOEXT2(mp);
 	dev = ump->um_dev;
 restart:
-	if ((error = ufs_ihashget(dev, ino, flags, vpp)) != 0)
+	if ((error = ext2_ihashget(dev, ino, flags, vpp)) != 0)
 		return (error);
 	if (*vpp != NULL)
 		return (0);
@@ -1048,17 +1013,13 @@ restart:
 	ip->i_e2fs = fs = ump->um_e2fs;
 	ip->i_dev = dev;
 	ip->i_number = ino;
-#if QUOTA
-	for (i = 0; i < MAXQUOTAS; i++)
-		ip->i_dquot[i] = NODQUOT;
-#endif
 	/*
 	 * Put it onto its hash chain and lock it so that other requests for
 	 * this inode will block if they arrive while we are sleeping waiting
 	 * for old data structures to be purged or for the contents of the
 	 * disk portion of this inode to be read.
 	 */
-	ufs_ihashins(ip);
+	ext2_ihashins(ip);
 
 	if (ext2fs_inode_hash_lock < 0)
 		wakeup(&ext2fs_inode_hash_lock);
@@ -1082,8 +1043,8 @@ printf("ext2_vget(%d) dbn= %d ", ino, fsbtodb(fs, ino_to_fsba(fs, ino)));
 		return (error);
 	}
 	/* convert ext2 inode to dinode */
-	ext2_ei2di((struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE *
-			ino_to_fsbo(fs, ino)), &ip->i_din);
+	ext2_ei2i((struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE *
+			ino_to_fsbo(fs, ino)), ip);
 	ip->i_block_group = ino_to_cg(fs, ino);
 	ip->i_next_alloc_block = 0;
 	ip->i_next_alloc_goal = 0;
@@ -1107,7 +1068,7 @@ printf("ext2_vget(%d) dbn= %d ", ino, fsbtodb(fs, ino_to_fsba(fs, ino)));
 	 * Initialize the vnode from the inode, check for aliases.
 	 * Note that the underlying vnode may have changed.
 	 */
-	if ((error = ufs_vinit(mp, ext2_specop_p, ext2_fifoop_p, &vp)) != 0) {
+	if ((error = ext2_vinit(mp, ext2_specop_p, ext2_fifoop_p, &vp)) != 0) {
 		vput(vp);
 		*vpp = NULL;
 		return (error);
@@ -1146,15 +1107,32 @@ ext2_fhtovp(mp, fhp, vpp)
 	struct fid *fhp;
 	struct vnode **vpp;
 {
+	struct inode *ip;
 	register struct ufid *ufhp;
+	struct vnode *nvp;
 	struct ext2_sb_info *fs;
+	int error;
 
 	ufhp = (struct ufid *)fhp;
-	fs = VFSTOUFS(mp)->um_e2fs;
+	fs = VFSTOEXT2(mp)->um_e2fs;
 	if (ufhp->ufid_ino < ROOTINO ||
 	    ufhp->ufid_ino >= fs->s_groups_count * fs->s_es->s_inodes_per_group)
 		return (ESTALE);
-	return (ufs_fhtovp(mp, ufhp, vpp));
+
+	error = VFS_VGET(mp, ufhp->ufid_ino, LK_EXCLUSIVE, &nvp);
+	if (error) {
+		*vpp = NULLVP;
+		return (error);
+	}
+	ip = VTOI(nvp);
+	if (ip->i_mode == 0 ||
+	    ip->i_gen != ufhp->ufid_gen || ip->i_nlink <= 0) {
+		vput(nvp);
+		*vpp = NULLVP;
+		return (ESTALE);
+	}
+	*vpp = nvp;
+	return (0);
 }
 
 /*
@@ -1182,7 +1160,7 @@ ext2_vptofh(vp, fhp)
  */
 static int
 ext2_sbupdate(mp, waitfor)
-	struct ufsmount *mp;
+	struct ext2mount *mp;
 	int waitfor;
 {
 	register struct ext2_sb_info *fs = mp->um_e2fs;
@@ -1207,3 +1185,34 @@ printf("\nupdating superblock, waitfor=%s\n", waitfor == MNT_WAIT ? "yes":"no");
 
 	return (error);
 }
+
+/*
+ * Return the root of a filesystem.
+ */
+static int
+ext2_root(mp, vpp)
+	struct mount *mp;
+	struct vnode **vpp;
+{
+	struct vnode *nvp;
+	int error;
+
+	error = VFS_VGET(mp, (ino_t)ROOTINO, LK_EXCLUSIVE, &nvp);
+	if (error)
+		return (error);
+	*vpp = nvp;
+	return (0);
+}
+
+static int
+ext2_init(struct vfsconf *vfsp)
+{
+	static int done;
+
+	if (done)
+		return (0);
+	done = 1;
+	ext2_ihashinit();
+
+	return (0);
+}
diff --git a/sys/gnu/fs/ext2fs/ext2_vnops.c b/sys/gnu/fs/ext2fs/ext2_vnops.c
index 180ac3db063a..ba7b714cdaf9 100644
--- a/sys/gnu/fs/ext2fs/ext2_vnops.c
+++ b/sys/gnu/fs/ext2fs/ext2_vnops.c
@@ -46,34 +46,38 @@
  * $FreeBSD$
  */
 
-#include "opt_quota.h"
 #include "opt_suiddir.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/resourcevar.h>
 #include <sys/kernel.h>
+#include <sys/fcntl.h>
 #include <sys/stat.h>
 #include <sys/bio.h>
 #include <sys/buf.h>
 #include <sys/proc.h>
 #include <sys/mount.h>
+#include <sys/unistd.h>
 #include <sys/time.h>
 #include <sys/vnode.h>
 #include <sys/namei.h>
+#include <sys/lockf.h>
+#include <sys/event.h>
+#include <sys/conf.h>
+#include <sys/file.h>
 
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 #include <vm/vnode_pager.h>
 
+#include <fs/fifofs/fifo.h>
+
 #include <sys/signalvar.h>
 #include <ufs/ufs/dir.h>
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-#include <ufs/ufs/ufsmount.h>
-#include <ufs/ufs/ufs_extern.h>
 
+#include <gnu/ext2fs/inode.h>
+#include <gnu/ext2fs/ext2_mount.h>
 #include <gnu/ext2fs/ext2_fs_sb.h>
 #include <gnu/ext2fs/fs.h>
 #include <gnu/ext2fs/ext2_extern.h>
@@ -81,38 +85,81 @@
 
 static int ext2_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *);
 
-static int ext2_fsync(struct vop_fsync_args *);
-static int ext2_read(struct vop_read_args *);
-static int ext2_write(struct vop_write_args *);
-static int ext2_remove(struct vop_remove_args *);
-static int ext2_link(struct vop_link_args *);
-static int ext2_rename(struct vop_rename_args *);
-static int ext2_mkdir(struct vop_mkdir_args *);
-static int ext2_rmdir(struct vop_rmdir_args *);
+static int ext2_access(struct vop_access_args *);
+static int ext2_advlock(struct vop_advlock_args *);
+static int ext2_chmod(struct vnode *, int, struct ucred *, struct thread *);
+static int ext2_chown(struct vnode *, uid_t, gid_t, struct ucred *,
+    struct thread *);
+static int ext2_close(struct vop_close_args *);
 static int ext2_create(struct vop_create_args *);
+static int ext2_fsync(struct vop_fsync_args *);
+static int ext2_getattr(struct vop_getattr_args *);
+static int ext2_kqfilter(struct vop_kqfilter_args *ap);
+static int ext2_link(struct vop_link_args *);
+static int ext2_mkdir(struct vop_mkdir_args *);
 static int ext2_mknod(struct vop_mknod_args *);
+static int ext2_open(struct vop_open_args *);
+static int ext2_pathconf(struct vop_pathconf_args *);
+static int ext2_print(struct vop_print_args *);
+static int ext2_read(struct vop_read_args *);
+static int ext2_readlink(struct vop_readlink_args *);
+static int ext2_remove(struct vop_remove_args *);
+static int ext2_rename(struct vop_rename_args *);
+static int ext2_rmdir(struct vop_rmdir_args *);
+static int ext2_setattr(struct vop_setattr_args *);
+static int ext2_strategy(struct vop_strategy_args *);
 static int ext2_symlink(struct vop_symlink_args *);
+static int ext2_write(struct vop_write_args *);
+static int ext2fifo_close(struct vop_close_args *);
+static int ext2fifo_kqfilter(struct vop_kqfilter_args *);
+static int ext2fifo_read(struct vop_read_args *);
+static int ext2fifo_write(struct vop_write_args *);
+static int ext2spec_close(struct vop_close_args *);
+static int ext2spec_read(struct vop_read_args *);
+static int ext2spec_write(struct vop_write_args *);
+static int filt_ext2read(struct knote *kn, long hint);
+static int filt_ext2write(struct knote *kn, long hint);
+static int filt_ext2vnode(struct knote *kn, long hint);
+static void filt_ext2detach(struct knote *kn);
 
-/* Global vfs data structures for ufs. */
+/* Global vfs data structures for ext2. */
 vop_t **ext2_vnodeop_p;
 static struct vnodeopv_entry_desc ext2_vnodeop_entries[] = {
-	{ &vop_default_desc,		(vop_t *) ufs_vnoperate },
+	{ &vop_default_desc,		(vop_t *) vop_defaultop },
+	{ &vop_access_desc,		(vop_t *) ext2_access },
+	{ &vop_advlock_desc,		(vop_t *) ext2_advlock },
+	{ &vop_bmap_desc,		(vop_t *) ext2_bmap },
 	{ &vop_cachedlookup_desc,	(vop_t *) ext2_lookup },
+	{ &vop_close_desc,		(vop_t *) ext2_close },
+	{ &vop_create_desc,		(vop_t *) ext2_create },
 	{ &vop_fsync_desc,		(vop_t *) ext2_fsync },
+	{ &vop_getattr_desc,		(vop_t *) ext2_getattr },
+	{ &vop_getwritemount_desc,	(vop_t *) vop_stdgetwritemount },
 	{ &vop_inactive_desc,		(vop_t *) ext2_inactive },
+	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
+	{ &vop_link_desc,		(vop_t *) ext2_link },
+	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
 	{ &vop_lookup_desc,		(vop_t *) vfs_cache_lookup },
+	{ &vop_mkdir_desc,		(vop_t *) ext2_mkdir },
+	{ &vop_mknod_desc,		(vop_t *) ext2_mknod },
+	{ &vop_open_desc,		(vop_t *) ext2_open },
+	{ &vop_pathconf_desc,		(vop_t *) ext2_pathconf },
+	{ &vop_poll_desc,		(vop_t *) vop_stdpoll },
+	{ &vop_kqfilter_desc,		(vop_t *) ext2_kqfilter },
+	{ &vop_print_desc,		(vop_t *) ext2_print },
 	{ &vop_read_desc,		(vop_t *) ext2_read },
 	{ &vop_readdir_desc,		(vop_t *) ext2_readdir },
+	{ &vop_readlink_desc,		(vop_t *) ext2_readlink },
 	{ &vop_reallocblks_desc,	(vop_t *) ext2_reallocblks },
-	{ &vop_write_desc,		(vop_t *) ext2_write },
+	{ &vop_reclaim_desc,		(vop_t *) ext2_reclaim },
 	{ &vop_remove_desc,		(vop_t *) ext2_remove },
-	{ &vop_link_desc,		(vop_t *) ext2_link },
 	{ &vop_rename_desc,		(vop_t *) ext2_rename },
-	{ &vop_mkdir_desc,		(vop_t *) ext2_mkdir },
 	{ &vop_rmdir_desc,		(vop_t *) ext2_rmdir },
-	{ &vop_create_desc,		(vop_t *) ext2_create },
-	{ &vop_mknod_desc,		(vop_t *) ext2_mknod },
+	{ &vop_setattr_desc,		(vop_t *) ext2_setattr },
+	{ &vop_strategy_desc,		(vop_t *) ext2_strategy },
 	{ &vop_symlink_desc,		(vop_t *) ext2_symlink },
+	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
+	{ &vop_write_desc,		(vop_t *) ext2_write },
 	{ NULL, NULL }
 };
 static struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
@@ -120,9 +167,20 @@ static struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
 
 vop_t **ext2_specop_p;
 static struct vnodeopv_entry_desc ext2_specop_entries[] = {
-	{ &vop_default_desc,		(vop_t *) ufs_vnoperatespec },
+	{ &vop_default_desc,		(vop_t *) spec_vnoperate },
+	{ &vop_access_desc,		(vop_t *) ext2_access },
+	{ &vop_close_desc,		(vop_t *) ext2spec_close },
 	{ &vop_fsync_desc,		(vop_t *) ext2_fsync },
+	{ &vop_getattr_desc,		(vop_t *) ext2_getattr },
 	{ &vop_inactive_desc,		(vop_t *) ext2_inactive },
+	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
+	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
+	{ &vop_print_desc,		(vop_t *) ext2_print },
+	{ &vop_read_desc,		(vop_t *) ext2spec_read },
+	{ &vop_reclaim_desc,		(vop_t *) ext2_reclaim },
+	{ &vop_setattr_desc,		(vop_t *) ext2_setattr },
+	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
+	{ &vop_write_desc,		(vop_t *) ext2spec_write },
 	{ NULL, NULL }
 };
 static struct vnodeopv_desc ext2fs_specop_opv_desc =
@@ -130,9 +188,21 @@ static struct vnodeopv_desc ext2fs_specop_opv_desc =
 
 vop_t **ext2_fifoop_p;
 static struct vnodeopv_entry_desc ext2_fifoop_entries[] = {
-	{ &vop_default_desc,		(vop_t *) ufs_vnoperatefifo },
+	{ &vop_default_desc,		(vop_t *) fifo_vnoperate },
+	{ &vop_access_desc,		(vop_t *) ext2_access },
+	{ &vop_close_desc,		(vop_t *) ext2fifo_close },
 	{ &vop_fsync_desc,		(vop_t *) ext2_fsync },
+	{ &vop_getattr_desc,		(vop_t *) ext2_getattr },
 	{ &vop_inactive_desc,		(vop_t *) ext2_inactive },
+	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
+	{ &vop_kqfilter_desc,		(vop_t *) ext2fifo_kqfilter },
+	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
+	{ &vop_print_desc,		(vop_t *) ext2_print },
+	{ &vop_read_desc,		(vop_t *) ext2fifo_read },
+	{ &vop_reclaim_desc,		(vop_t *) ext2_reclaim },
+	{ &vop_setattr_desc,		(vop_t *) ext2_setattr },
+	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
+	{ &vop_write_desc,		(vop_t *) ext2fifo_write },
 	{ NULL, NULL }
 };
 static struct vnodeopv_desc ext2fs_fifoop_opv_desc =
@@ -144,9 +214,26 @@ static struct vnodeopv_desc ext2fs_fifoop_opv_desc =
 
 #include <gnu/ext2fs/ext2_readwrite.c>
 
+union _qcvt {
+	int64_t qcvt;
+	int32_t val[2];
+};
+#define SETHIGH(q, h) { \
+	union _qcvt tmp; \
+	tmp.qcvt = (q); \
+	tmp.val[_QUAD_HIGHWORD] = (h); \
+	(q) = tmp.qcvt; \
+}
+#define SETLOW(q, l) { \
+	union _qcvt tmp; \
+	tmp.qcvt = (q); \
+	tmp.val[_QUAD_LOWWORD] = (l); \
+	(q) = tmp.qcvt; \
+}
+
 /*
  * A virgin directory (no blushing please).
- * Note that the type and namlen fields are reversed relative to ufs.
+ * Note that the type and namlen fields are reversed relative to ext2.
  * Also, we don't use `struct odirtemplate', since it would just cause
  * endianness problems.
  */
@@ -159,6 +246,39 @@ static struct dirtemplate omastertemplate = {
 	0, DIRBLKSIZ - 12, 2, EXT2_FT_UNKNOWN, ".."
 };
 
+void
+ext2_itimes(vp)
+	struct vnode *vp;
+{
+	struct inode *ip;
+	struct timespec ts;
+
+	ip = VTOI(vp);
+	if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0)
+		return;
+	if ((vp->v_type == VBLK || vp->v_type == VCHR))
+		ip->i_flag |= IN_LAZYMOD;
+	else
+		ip->i_flag |= IN_MODIFIED;
+	if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
+		vfs_timestamp(&ts);
+		if (ip->i_flag & IN_ACCESS) {
+			ip->i_atime = ts.tv_sec;
+			ip->i_atimensec = ts.tv_nsec;
+		}
+		if (ip->i_flag & IN_UPDATE) {
+			ip->i_mtime = ts.tv_sec;
+			ip->i_mtimensec = ts.tv_nsec;
+			ip->i_modrev++;
+		}
+		if (ip->i_flag & IN_CHANGE) {
+			ip->i_ctime = ts.tv_sec;
+			ip->i_ctimensec = ts.tv_nsec;
+		}
+	}
+	ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);
+}
+
 /*
  * Create a regular file
  */
@@ -181,6 +301,375 @@ ext2_create(ap)
 	return (0);
 }
 
+/*
+ * Open called.
+ *
+ * Nothing to do.
+ */
+int
+ext2_open(ap)
+	struct vop_open_args /* {
+		struct vnode *a_vp;
+		int  a_mode;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+
+	/*
+	 * Files marked append-only must be opened for appending.
+	 */
+	if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
+	    (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
+		return (EPERM);
+	return (0);
+}
+
+/*
+ * Close called.
+ *
+ * Update the times on the inode.
+ */
+static int
+ext2_close(ap)
+	struct vop_close_args /* {
+		struct vnode *a_vp;
+		int  a_fflag;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+	struct mount *mp;
+
+	mtx_lock(&vp->v_interlock);
+	if (vp->v_usecount > 1) {
+		ext2_itimes(vp);
+		mtx_unlock(&vp->v_interlock);
+	} else {
+		mtx_unlock(&vp->v_interlock);
+		/*
+		 * If we are closing the last reference to an unlinked
+		 * file, then it will be freed by the inactive routine.
+		 * Because the freeing causes a the filesystem to be
+		 * modified, it must be held up during periods when the
+		 * filesystem is suspended.
+		 *
+		 * XXX - EAGAIN is returned to prevent vn_close from
+		 * repeating the vrele operation.
+		 */
+		if (vp->v_type == VREG && VTOI(vp)->i_nlink == 0) {
+			(void) vn_start_write(vp, &mp, V_WAIT);
+			vrele(vp);
+			vn_finished_write(mp);
+			return (EAGAIN);
+		}
+	}
+	return (0);
+}
+
+static int
+ext2_access(ap)
+	struct vop_access_args /* {
+		struct vnode *a_vp;
+		int  a_mode;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
+	mode_t mode = ap->a_mode;
+	int error;
+
+	/*
+	 * Disallow write attempts on read-only file systems;
+	 * unless the file is a socket, fifo, or a block or
+	 * character device resident on the file system.
+	 */
+	if (mode & VWRITE) {
+		switch (vp->v_type) {
+		case VDIR:
+		case VLNK:
+		case VREG:
+			if (vp->v_mount->mnt_flag & MNT_RDONLY)
+				return (EROFS);
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* If immutable bit set, nobody gets to write it. */
+	if ((mode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT)))
+		return (EPERM);
+
+	error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid,
+	    ap->a_mode, ap->a_cred, NULL);
+	return (error);
+}
+
+static int
+ext2_getattr(ap)
+	struct vop_getattr_args /* {
+		struct vnode *a_vp;
+		struct vattr *a_vap;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
+	struct vattr *vap = ap->a_vap;
+
+	ext2_itimes(vp);
+	/*
+	 * Copy from inode table
+	 */
+	vap->va_fsid = dev2udev(ip->i_dev);
+	vap->va_fileid = ip->i_number;
+	vap->va_mode = ip->i_mode & ~IFMT;
+	vap->va_nlink = ip->i_nlink;
+	vap->va_uid = ip->i_uid;
+	vap->va_gid = ip->i_gid;
+	vap->va_rdev = ip->i_rdev;
+	vap->va_size = ip->i_size;
+	vap->va_atime.tv_sec = ip->i_atime;
+	vap->va_atime.tv_nsec = ip->i_atimensec;
+	vap->va_mtime.tv_sec = ip->i_mtime;
+	vap->va_mtime.tv_nsec = ip->i_mtimensec;
+	vap->va_ctime.tv_sec = ip->i_ctime;
+	vap->va_ctime.tv_nsec = ip->i_ctimensec;
+	vap->va_flags = ip->i_flags;
+	vap->va_gen = ip->i_gen;
+	vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
+	vap->va_bytes = dbtob((u_quad_t)ip->i_blocks);
+	vap->va_type = IFTOVT(ip->i_mode);
+	vap->va_filerev = ip->i_modrev;
+	return (0);
+}
+
+/*
+ * Set attribute vnode op. called from several syscalls
+ */
+int
+ext2_setattr(ap)
+	struct vop_setattr_args /* {
+		struct vnode *a_vp;
+		struct vattr *a_vap;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct vattr *vap = ap->a_vap;
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
+	struct ucred *cred = ap->a_cred;
+	struct thread *td = ap->a_td;
+	int error;
+
+	/*
+	 * Check for unsettable attributes.
+	 */
+	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
+	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
+	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
+	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
+		return (EINVAL);
+	}
+	if (vap->va_flags != VNOVAL) {
+		if (vp->v_mount->mnt_flag & MNT_RDONLY)
+			return (EROFS);
+		/*
+		 * Callers may only modify the file flags on objects they
+		 * have VADMIN rights for.
+		 */
+		if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
+			return (error);
+		/*
+		 * Unprivileged processes and privileged processes in
+		 * jail() are not permitted to unset system flags, or
+		 * modify flags if any system flags are set.
+		 * Privileged non-jail processes may not modify system flags
+		 * if securelevel > 0 and any existing system flags are set.
+		 */
+		if (!suser_cred(cred, PRISON_ROOT)) {
+			if (ip->i_flags
+			    & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) {
+				error = securelevel_gt(cred, 0);
+				if (error)
+					return (error);
+			}
+			ip->i_flags = vap->va_flags;
+		} else {
+			if (ip->i_flags
+			    & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) ||
+			    (vap->va_flags & UF_SETTABLE) != vap->va_flags)
+				return (EPERM);
+			ip->i_flags &= SF_SETTABLE;
+			ip->i_flags |= (vap->va_flags & UF_SETTABLE);
+		}
+		ip->i_flag |= IN_CHANGE;
+		if (vap->va_flags & (IMMUTABLE | APPEND))
+			return (0);
+	}
+	if (ip->i_flags & (IMMUTABLE | APPEND))
+		return (EPERM);
+	/*
+	 * Go through the fields and update iff not VNOVAL.
+	 */
+	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
+		if (vp->v_mount->mnt_flag & MNT_RDONLY)
+			return (EROFS);
+		if ((error = ext2_chown(vp, vap->va_uid, vap->va_gid, cred,
+		    td)) != 0)
+			return (error);
+	}
+	if (vap->va_size != VNOVAL) {
+		/*
+		 * Disallow write attempts on read-only file systems;
+		 * unless the file is a socket, fifo, or a block or
+		 * character device resident on the file system.
+		 */
+		switch (vp->v_type) {
+		case VDIR:
+			return (EISDIR);
+		case VLNK:
+		case VREG:
+			if (vp->v_mount->mnt_flag & MNT_RDONLY)
+				return (EROFS);
+			break;
+		default:
+			break;
+		}
+		if ((error = ext2_truncate(vp, vap->va_size, 0, cred, td)) != 0)
+			return (error);
+	}
+	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+		if (vp->v_mount->mnt_flag & MNT_RDONLY)
+			return (EROFS);
+		/*
+		 * From utimes(2):
+		 * If times is NULL, ... The caller must be the owner of
+		 * the file, have permission to write the file, or be the
+		 * super-user.
+		 * If times is non-NULL, ... The caller must be the owner of
+		 * the file or be the super-user.
+		 */
+		if ((error = VOP_ACCESS(vp, VADMIN, cred, td)) &&
+		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
+		    (error = VOP_ACCESS(vp, VWRITE, cred, td))))
+			return (error);
+		if (vap->va_atime.tv_sec != VNOVAL)
+			ip->i_flag |= IN_ACCESS;
+		if (vap->va_mtime.tv_sec != VNOVAL)
+			ip->i_flag |= IN_CHANGE | IN_UPDATE;
+		ext2_itimes(vp);
+		if (vap->va_atime.tv_sec != VNOVAL) {
+			ip->i_atime = vap->va_atime.tv_sec;
+			ip->i_atimensec = vap->va_atime.tv_nsec;
+		}
+		if (vap->va_mtime.tv_sec != VNOVAL) {
+			ip->i_mtime = vap->va_mtime.tv_sec;
+			ip->i_mtimensec = vap->va_mtime.tv_nsec;
+		}
+		error = ext2_update(vp, 0);
+		if (error)
+			return (error);
+	}
+	error = 0;
+	if (vap->va_mode != (mode_t)VNOVAL) {
+		if (vp->v_mount->mnt_flag & MNT_RDONLY)
+			return (EROFS);
+		error = ext2_chmod(vp, (int)vap->va_mode, cred, td);
+	}
+	VN_KNOTE(vp, NOTE_ATTRIB);
+	return (error);
+}
+
+/*
+ * Change the mode on a file.
+ * Inode must be locked before calling.
+ */
+static int
+ext2_chmod(vp, mode, cred, td)
+	struct vnode *vp;
+	int mode;
+	struct ucred *cred;
+	struct thread *td;
+{
+	struct inode *ip = VTOI(vp);
+	int error;
+
+	/*
+	 * To modify the permissions on a file, must possess VADMIN
+	 * for that file.
+	 */
+	if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
+		return (error);
+	/*
+	 * Privileged processes may set the sticky bit on non-directories,
+	 * as well as set the setgid bit on a file with a group that the
+	 * process is not a member of.
+	 */
+	if (suser_cred(cred, PRISON_ROOT)) {
+		if (vp->v_type != VDIR && (mode & S_ISTXT))
+			return (EFTYPE);
+		if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
+			return (EPERM);
+	}
+	ip->i_mode &= ~ALLPERMS;
+	ip->i_mode |= (mode & ALLPERMS);
+	ip->i_flag |= IN_CHANGE;
+	return (0);
+}
+
+/*
+ * Perform chown operation on inode ip;
+ * inode must be locked prior to call.
+ */
+static int
+ext2_chown(vp, uid, gid, cred, td)
+	struct vnode *vp;
+	uid_t uid;
+	gid_t gid;
+	struct ucred *cred;
+	struct thread *td;
+{
+	struct inode *ip = VTOI(vp);
+	uid_t ouid;
+	gid_t ogid;
+	int error = 0;
+
+	if (uid == (uid_t)VNOVAL)
+		uid = ip->i_uid;
+	if (gid == (gid_t)VNOVAL)
+		gid = ip->i_gid;
+	/*
+	 * To modify the ownership of a file, must possess VADMIN
+	 * for that file.
+	 */
+	if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
+		return (error);
+	/*
+	 * To change the owner of a file, or change the group of a file
+	 * to a group of which we are not a member, the caller must
+	 * have privilege.
+	 */
+	if ((uid != ip->i_uid || 
+	    (gid != ip->i_gid && !groupmember(gid, cred))) &&
+	    (error = suser_cred(cred, PRISON_ROOT)))
+		return (error);
+	ogid = ip->i_gid;
+	ouid = ip->i_uid;
+	ip->i_gid = gid;
+	ip->i_uid = uid;
+	ip->i_flag |= IN_CHANGE;
+	if (suser_cred(cred, PRISON_ROOT) && (ouid != uid || ogid != gid))
+		ip->i_mode &= ~(ISUID | ISGID);
+	return (0);
+}
+
 /*
  * Synch an open file.
  */
@@ -241,7 +730,7 @@ loop:
 #endif
 	}
 	splx(s);
-	return (UFS_UPDATE(ap->a_vp, ap->a_waitfor == MNT_WAIT));
+	return (ext2_update(ap->a_vp, ap->a_waitfor == MNT_WAIT));
 }
 
 /*
@@ -341,7 +830,7 @@ ext2_link(ap)
 
 #ifdef DIAGNOSTIC
 	if ((cnp->cn_flags & HASBUF) == 0)
-		panic("ufs_link: no name");
+		panic("ext2_link: no name");
 #endif
 	if (tdvp->v_mount != vp->v_mount) {
 		error = EXDEV;
@@ -361,7 +850,7 @@ ext2_link(ap)
 	}
 	ip->i_nlink++;
 	ip->i_flag |= IN_CHANGE;
-	error = UFS_UPDATE(vp, 1);
+	error = ext2_update(vp, 1);
 	if (!error)
 		error = ext2_direnter(ip, tdvp, cnp);
 	if (error) {
@@ -406,7 +895,7 @@ ext2_rename(ap)
 #ifdef DIAGNOSTIC
 	if ((tcnp->cn_flags & HASBUF) == 0 ||
 	    (fcnp->cn_flags & HASBUF) == 0)
-		panic("ufs_rename: no name");
+		panic("ext2_rename: no name");
 #endif
 	/*
 	 * Check for cross-device rename.
@@ -447,7 +936,7 @@ abortit:
 			 * completed before the lookup.
 			 */
 #ifdef UFS_RENAME_DEBUG
-			printf("ufs_rename: fvp == tvp for directories\n");
+			printf("ext2_rename: fvp == tvp for directories\n");
 #endif
 			error = ENOENT;
 			goto abortit;
@@ -474,7 +963,7 @@ abortit:
 			vrele(fdvp);
 		if (fvp == NULL) {
 #ifdef UFS_RENAME_DEBUG
-			printf("ufs_rename: from name disappeared\n");
+			printf("ext2_rename: from name disappeared\n");
 #endif
 			return (ENOENT);
 		}
@@ -536,7 +1025,7 @@ abortit:
 	 */
 	ip->i_nlink++;
 	ip->i_flag |= IN_CHANGE;
-	if ((error = UFS_UPDATE(fvp, 1)) != 0) {
+	if ((error = ext2_update(fvp, 1)) != 0) {
 		VOP_UNLOCK(fvp, 0, td);
 		goto bad;
 	}
@@ -582,7 +1071,7 @@ abortit:
 	 */
 	if (xp == NULL) {
 		if (dp->i_dev != ip->i_dev)
-			panic("ufs_rename: EXDEV");
+			panic("ext2_rename: EXDEV");
 		/*
 		 * Account for ".." in new directory.
 		 * When source and destination have the same
@@ -595,7 +1084,7 @@ abortit:
 			}
 			dp->i_nlink++;
 			dp->i_flag |= IN_CHANGE;
-			error = UFS_UPDATE(tdvp, 1);
+			error = ext2_update(tdvp, 1);
 			if (error)
 				goto bad;
 		}
@@ -604,19 +1093,19 @@ abortit:
 			if (doingdirectory && newparent) {
 				dp->i_nlink--;
 				dp->i_flag |= IN_CHANGE;
-				(void)UFS_UPDATE(tdvp, 1);
+				(void)ext2_update(tdvp, 1);
 			}
 			goto bad;
 		}
 		vput(tdvp);
 	} else {
 		if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
-			panic("ufs_rename: EXDEV");
+			panic("ext2_rename: EXDEV");
 		/*
 		 * Short circuit rename(foo, foo).
 		 */
 		if (xp->i_number == ip->i_number)
-			panic("ufs_rename: same file");
+			panic("ext2_rename: same file");
 		/*
 		 * If the parent directory is "sticky", then the user must
 		 * own the parent directory, or the destination of the rename,
@@ -676,8 +1165,8 @@ abortit:
 		xp->i_nlink--;
 		if (doingdirectory) {
 			if (--xp->i_nlink != 0)
-				panic("ufs_rename: linked directory");
-			error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC,
+				panic("ext2_rename: linked directory");
+			error = ext2_truncate(tvp, (off_t)0, IO_SYNC,
 			    tcnp->cn_cred, tcnp->cn_thread);
 		}
 		xp->i_flag |= IN_CHANGE;
@@ -702,7 +1191,7 @@ abortit:
 		 * From name has disappeared.
 		 */
 		if (doingdirectory)
-			panic("ufs_rename: lost dir entry");
+			panic("ext2_rename: lost dir entry");
 		vrele(ap->a_fvp);
 		return (0);
 	}
@@ -718,7 +1207,7 @@ abortit:
 	 */
 	if (xp != ip) {
 		if (doingdirectory)
-			panic("ufs_rename: lost dir entry");
+			panic("ext2_rename: lost dir entry");
 	} else {
 		/*
 		 * If the source is a directory with a
@@ -739,7 +1228,7 @@ abortit:
 				if (namlen != 2 ||
 				    dirbuf.dotdot_name[0] != '.' ||
 				    dirbuf.dotdot_name[1] != '.') {
-					ufs_dirbad(xp, (doff_t)12,
+					ext2_dirbad(xp, (doff_t)12,
 					    "rename: mangled dir");
 				} else {
 					dirbuf.dotdot_ino = newparent;
@@ -807,7 +1296,7 @@ ext2_mkdir(ap)
 
 #ifdef DIAGNOSTIC
 	if ((cnp->cn_flags & HASBUF) == 0)
-		panic("ufs_mkdir: no name");
+		panic("ext2_mkdir: no name");
 #endif
 	dp = VTOI(dvp);
 	if ((nlink_t)dp->i_nlink >= LINK_MAX) {
@@ -821,17 +1310,13 @@ ext2_mkdir(ap)
 	 * but not have it entered in the parent directory. The entry is
 	 * made later after writing "." and ".." entries.
 	 */
-	error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp);
+	error = ext2_valloc(dvp, dmode, cnp->cn_cred, &tvp);
 	if (error)
 		goto out;
 	ip = VTOI(tvp);
 	ip->i_gid = dp->i_gid;
 #ifdef SUIDDIR
 	{
-#ifdef QUOTA
-		struct ucred ucred, *ucp;
-		ucp = cnp->cn_cred;
-#endif
 		/*
 		 * if we are hacking owners here, (only do this where told to)
 		 * and we are not giving it TOO root, (would subvert quotas)
@@ -844,44 +1329,12 @@ ext2_mkdir(ap)
 		   (dp->i_mode & ISUID) && dp->i_uid) {
 			dmode |= ISUID;
 			ip->i_uid = dp->i_uid;
-#ifdef QUOTA
-			if (dp->i_uid != cnp->cn_cred->cr_uid) {
-				/*
-				 * make sure the correct user gets charged
-				 * for the space.
-				 * Make a dummy credential for the victim.
-				 * XXX This seems to never be accessed out of
-				 * our context so a stack variable is ok.
-				 */
-				ucred.cr_ref = 1;
-				ucred.cr_uid = ip->i_uid;
-				ucred.cr_ngroups = 1;
-				ucred.cr_groups[0] = dp->i_gid;
-				ucp = &ucred;
-			}
-#endif
 		} else {
 			ip->i_uid = cnp->cn_cred->cr_uid;
 		}
-#ifdef QUOTA
-		if ((error = getinoquota(ip)) ||
-	    	(error = chkiq(ip, 1, ucp, 0))) {
-			UFS_VFREE(tvp, ip->i_number, dmode);
-			vput(tvp);
-			return (error);
-		}
-#endif
 	}
 #else
 	ip->i_uid = cnp->cn_cred->cr_uid;
-#ifdef QUOTA
-	if ((error = getinoquota(ip)) ||
-	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
-		UFS_VFREE(tvp, ip->i_number, dmode);
-		vput(tvp);
-		return (error);
-	}
-#endif
 #endif
 	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
 	ip->i_mode = dmode;
@@ -889,7 +1342,7 @@ ext2_mkdir(ap)
 	ip->i_nlink = 2;
 	if (cnp->cn_flags & ISWHITEOUT)
 		ip->i_flags |= UF_OPAQUE;
-	error = UFS_UPDATE(tvp, 1);
+	error = ext2_update(tvp, 1);
 
 	/*
 	 * Bump link count in parent directory
@@ -899,7 +1352,7 @@ ext2_mkdir(ap)
 	 */
 	dp->i_nlink++;
 	dp->i_flag |= IN_CHANGE;
-	error = UFS_UPDATE(dvp, 1);
+	error = ext2_update(dvp, 1);
 	if (error)
 		goto bad;
 
@@ -926,8 +1379,9 @@ ext2_mkdir(ap)
 		dp->i_flag |= IN_CHANGE;
 		goto bad;
 	}
-	if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
-		panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
+	if (DIRBLKSIZ > VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
+		/* XXX should grow with balloc() */
+		panic("ext2_mkdir: blksize");
 	else {
 		ip->i_size = DIRBLKSIZ;
 		ip->i_flag |= IN_CHANGE;
@@ -1018,7 +1472,7 @@ ext2_rmdir(ap)
 	 * worry about them later.
 	 */
 	ip->i_nlink -= 2;
-	error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, td);
+	error = ext2_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred, td);
 	cache_purge(ITOV(ip));
 	vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
 out:
@@ -1062,6 +1516,362 @@ ext2_symlink(ap)
 	return (error);
 }
 
+/*
+ * Return target name of a symbolic link
+ */
+static int
+ext2_readlink(ap)
+	struct vop_readlink_args /* {
+		struct vnode *a_vp;
+		struct uio *a_uio;
+		struct ucred *a_cred;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
+	int isize;
+
+	isize = ip->i_size;
+	if (isize < vp->v_mount->mnt_maxsymlinklen) {
+		uiomove((char *)ip->i_shortlink, isize, ap->a_uio);
+		return (0);
+	}
+	return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
+}
+
+/*
+ * Calculate the logical to physical mapping if not done already,
+ * then call the device strategy routine.
+ *
+ * In order to be able to swap to a file, the ext2_bmaparray() operation may not
+ * deadlock on memory.  See ext2_bmap() for details.
+ */
+int
+ext2_strategy(ap)
+	struct vop_strategy_args /* {
+		struct vnode *a_vp;
+		struct buf *a_bp;
+	} */ *ap;
+{
+	struct buf *bp = ap->a_bp;
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip;
+	daddr_t blkno;
+	int error;
+
+	ip = VTOI(vp);
+	if (vp->v_type == VBLK || vp->v_type == VCHR)
+		panic("ext2_strategy: spec");
+	if (bp->b_blkno == bp->b_lblkno) {
+		error = ext2_bmaparray(vp, bp->b_lblkno, &blkno, NULL, NULL);
+		bp->b_blkno = blkno;
+		if (error) {
+			bp->b_error = error;
+			bp->b_ioflags |= BIO_ERROR;
+			bufdone(bp);
+			return (error);
+		}
+		if ((long)bp->b_blkno == -1)
+			vfs_bio_clrbuf(bp);
+	}
+	if ((long)bp->b_blkno == -1) {
+		bufdone(bp);
+		return (0);
+	}
+	vp = ip->i_devvp;
+	bp->b_dev = vp->v_rdev;
+	VOP_STRATEGY(vp, bp);
+	return (0);
+}
+
+/*
+ * Print out the contents of an inode.
+ */
+int
+ext2_print(ap)
+	struct vop_print_args /* {
+		struct vnode *a_vp;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
+
+	printf("tag VT_UFS, ino %lu, on dev %s (%d, %d)",
+	    (u_long)ip->i_number, devtoname(ip->i_dev), major(ip->i_dev),
+	    minor(ip->i_dev));
+	if (vp->v_type == VFIFO)
+		fifo_printinfo(vp);
+	lockmgr_printinfo(&vp->v_lock);
+	printf("\n");
+	return (0);
+}
+
+/*
+ * Read wrapper for special devices.
+ */
+int
+ext2spec_read(ap)
+	struct vop_read_args /* {
+		struct vnode *a_vp;
+		struct uio *a_uio;
+		int  a_ioflag;
+		struct ucred *a_cred;
+	} */ *ap;
+{
+	int error, resid;
+	struct inode *ip;
+	struct uio *uio;
+
+	uio = ap->a_uio;
+	resid = uio->uio_resid;
+	error = VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap);
+	/*
+	 * The inode may have been revoked during the call, so it must not
+	 * be accessed blindly here or in the other wrapper functions.
+	 */
+	ip = VTOI(ap->a_vp);
+	if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
+		ip->i_flag |= IN_ACCESS;
+	return (error);
+}
+
+/*
+ * Write wrapper for special devices.
+ */
+int
+ext2spec_write(ap)
+	struct vop_write_args /* {
+		struct vnode *a_vp;
+		struct uio *a_uio;
+		int  a_ioflag;
+		struct ucred *a_cred;
+	} */ *ap;
+{
+	int error, resid;
+	struct inode *ip;
+	struct uio *uio;
+
+	uio = ap->a_uio;
+	resid = uio->uio_resid;
+	error = VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap);
+	ip = VTOI(ap->a_vp);
+	if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
+		VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
+	return (error);
+}
+
+/*
+ * Close wrapper for special devices.
+ *
+ * Update the times on the inode then do device close.
+ */
+int
+ext2spec_close(ap)
+	struct vop_close_args /* {
+		struct vnode *a_vp;
+		int  a_fflag;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+
+	mtx_lock(&vp->v_interlock);
+	if (vp->v_usecount > 1)
+		ext2_itimes(vp);
+	mtx_unlock(&vp->v_interlock);
+	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
+}
+
+/*
+ * Read wrapper for fifos.
+ */
+int
+ext2fifo_read(ap)
+	struct vop_read_args /* {
+		struct vnode *a_vp;
+		struct uio *a_uio;
+		int  a_ioflag;
+		struct ucred *a_cred;
+	} */ *ap;
+{
+	int error, resid;
+	struct inode *ip;
+	struct uio *uio;
+
+	uio = ap->a_uio;
+	resid = uio->uio_resid;
+	error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap);
+	ip = VTOI(ap->a_vp);
+	if ((ap->a_vp->v_mount->mnt_flag & MNT_NOATIME) == 0 && ip != NULL &&
+	    (uio->uio_resid != resid || (error == 0 && resid != 0)))
+		VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
+	return (error);
+}
+
+/*
+ * Write wrapper for fifos.
+ */
+int
+ext2fifo_write(ap)
+	struct vop_write_args /* {
+		struct vnode *a_vp;
+		struct uio *a_uio;
+		int  a_ioflag;
+		struct ucred *a_cred;
+	} */ *ap;
+{
+	int error, resid;
+	struct inode *ip;
+	struct uio *uio;
+
+	uio = ap->a_uio;
+	resid = uio->uio_resid;
+	error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap);
+	ip = VTOI(ap->a_vp);
+	if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
+		VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
+	return (error);
+}
+
+/*
+ * Close wrapper for fifos.
+ *
+ * Update the times on the inode then do device close.
+ */
+int
+ext2fifo_close(ap)
+	struct vop_close_args /* {
+		struct vnode *a_vp;
+		int  a_fflag;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+
+	mtx_lock(&vp->v_interlock);
+	if (vp->v_usecount > 1)
+		ext2_itimes(vp);
+	mtx_unlock(&vp->v_interlock);
+	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
+}
+
+/*
+ * Kqfilter wrapper for fifos.
+ *
+ * Fall through to ext2 kqfilter routines if needed 
+ */
+int
+ext2fifo_kqfilter(ap)
+	struct vop_kqfilter_args *ap;
+{
+	int error;
+
+	error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_kqfilter), ap);
+	if (error)
+		error = ext2_kqfilter(ap);
+	return (error);
+}
+
+/*
+ * Return POSIX pathconf information applicable to ext2 filesystems.
+ */
+int
+ext2_pathconf(ap)
+	struct vop_pathconf_args /* {
+		struct vnode *a_vp;
+		int a_name;
+		int *a_retval;
+	} */ *ap;
+{
+
+	switch (ap->a_name) {
+	case _PC_LINK_MAX:
+		*ap->a_retval = LINK_MAX;
+		return (0);
+	case _PC_NAME_MAX:
+		*ap->a_retval = NAME_MAX;
+		return (0);
+	case _PC_PATH_MAX:
+		*ap->a_retval = PATH_MAX;
+		return (0);
+	case _PC_PIPE_BUF:
+		*ap->a_retval = PIPE_BUF;
+		return (0);
+	case _PC_CHOWN_RESTRICTED:
+		*ap->a_retval = 1;
+		return (0);
+	case _PC_NO_TRUNC:
+		*ap->a_retval = 1;
+		return (0);
+	default:
+		return (EINVAL);
+	}
+	/* NOTREACHED */
+}
+
+/*
+ * Advisory record locking support
+ */
+static int
+ext2_advlock(ap)
+	struct vop_advlock_args /* {
+		struct vnode *a_vp;
+		caddr_t  a_id;
+		int  a_op;
+		struct flock *a_fl;
+		int  a_flags;
+	} */ *ap;
+{
+	struct inode *ip = VTOI(ap->a_vp);
+
+	return (lf_advlock(ap, &(ip->i_lockf), ip->i_size));
+}
+
+/*
+ * Initialize the vnode associated with a new inode, handle aliased
+ * vnodes.
+ */
+int
+ext2_vinit(mntp, specops, fifoops, vpp)
+	struct mount *mntp;
+	vop_t **specops;
+	vop_t **fifoops;
+	struct vnode **vpp;
+{
+	struct inode *ip;
+	struct vnode *vp;
+	struct timeval tv;
+
+	vp = *vpp;
+	ip = VTOI(vp);
+	switch(vp->v_type = IFTOVT(ip->i_mode)) {
+	case VCHR:
+	case VBLK:
+		vp->v_op = specops;
+		vp = addaliasu(vp, ip->i_rdev);
+		ip->i_vnode = vp;
+		break;
+	case VFIFO:
+		vp->v_op = fifoops;
+		break;
+	default:
+		break;
+
+	}
+	if (ip->i_number == ROOTINO)
+		vp->v_flag |= VROOT;
+	/*
+	 * Initialize modrev times
+	 */
+	getmicrouptime(&tv);
+	SETHIGH(ip->i_modrev, tv.tv_sec);
+	SETLOW(ip->i_modrev, tv.tv_usec * 4294);
+	*vpp = vp;
+	return (0);
+}
+
 /*
  * Allocate a new inode.
  */
@@ -1085,7 +1895,7 @@ ext2_makeinode(mode, dvp, vpp, cnp)
 	if ((mode & IFMT) == 0)
 		mode |= IFREG;
 
-	error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp);
+	error = ext2_valloc(dvp, mode, cnp->cn_cred, &tvp);
 	if (error) {
 		return (error);
 	}
@@ -1093,10 +1903,6 @@ ext2_makeinode(mode, dvp, vpp, cnp)
 	ip->i_gid = pdir->i_gid;
 #ifdef SUIDDIR
 	{
-#ifdef QUOTA
-		struct ucred ucred, *ucp;
-		ucp = cnp->cn_cred;
-#endif
 		/*
 		 * if we are
 		 * not the owner of the directory,
@@ -1110,43 +1916,12 @@ ext2_makeinode(mode, dvp, vpp, cnp)
 		     (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) {
 			ip->i_uid = pdir->i_uid;
 			mode &= ~07111;
-#ifdef QUOTA
-			/*
-			 * make sure the correct user gets charged
-			 * for the space.
-			 * Quickly knock up a dummy credential for the victim.
-			 * XXX This seems to never be accessed out of our
-			 * context so a stack variable is ok.
-			 */
-			ucred.cr_ref = 1;
-			ucred.cr_uid = ip->i_uid;
-			ucred.cr_ngroups = 1;
-			ucred.cr_groups[0] = pdir->i_gid;
-			ucp = &ucred;
-#endif
 		} else {
 			ip->i_uid = cnp->cn_cred->cr_uid;
 		}
-	
-#ifdef QUOTA
-		if ((error = getinoquota(ip)) ||
-	    	(error = chkiq(ip, 1, ucp, 0))) {
-			UFS_VFREE(tvp, ip->i_number, mode);
-			vput(tvp);
-			return (error);
-		}
-#endif
 	}
 #else
 	ip->i_uid = cnp->cn_cred->cr_uid;
-#ifdef QUOTA
-	if ((error = getinoquota(ip)) ||
-	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
-		UFS_VFREE(tvp, ip->i_number, mode);
-		vput(tvp);
-		return (error);
-	}
-#endif
 #endif
 	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
 	ip->i_mode = mode;
@@ -1162,7 +1937,7 @@ ext2_makeinode(mode, dvp, vpp, cnp)
 	/*
 	 * Make sure inode goes to disk before directory entry.
 	 */
-	error = UFS_UPDATE(tvp, 1);
+	error = ext2_update(tvp, 1);
 	if (error)
 		goto bad;
 	error = ext2_direnter(ip, dvp, cnp);
@@ -1182,3 +1957,106 @@ bad:
 	vput(tvp);
 	return (error);
 }
+
+static struct filterops ext2read_filtops = 
+	{ 1, NULL, filt_ext2detach, filt_ext2read };
+static struct filterops ext2write_filtops = 
+	{ 1, NULL, filt_ext2detach, filt_ext2write };
+static struct filterops ext2vnode_filtops = 
+	{ 1, NULL, filt_ext2detach, filt_ext2vnode };
+
+static int
+ext2_kqfilter(ap)
+	struct vop_kqfilter_args /* {
+		struct vnode *a_vp;
+		struct knote *a_kn;
+	} */ *ap;
+{
+	struct vnode *vp = ap->a_vp;
+	struct knote *kn = ap->a_kn;
+
+	switch (kn->kn_filter) {
+	case EVFILT_READ:
+		kn->kn_fop = &ext2read_filtops;
+		break;
+	case EVFILT_WRITE:
+		kn->kn_fop = &ext2write_filtops;
+		break;
+	case EVFILT_VNODE:
+		kn->kn_fop = &ext2vnode_filtops;
+		break;
+	default:
+		return (1);
+	}
+
+	kn->kn_hook = (caddr_t)vp;
+
+	if (vp->v_pollinfo == NULL)
+		v_addpollinfo(vp);
+	mtx_lock(&vp->v_pollinfo->vpi_lock);
+	SLIST_INSERT_HEAD(&vp->v_pollinfo->vpi_selinfo.si_note, kn, kn_selnext);
+	mtx_unlock(&vp->v_pollinfo->vpi_lock);
+
+	return (0);
+}
+
+static void
+filt_ext2detach(struct knote *kn)
+{
+	struct vnode *vp = (struct vnode *)kn->kn_hook;
+
+	KASSERT(vp->v_pollinfo != NULL, ("Mising v_pollinfo"));
+	mtx_lock(&vp->v_pollinfo->vpi_lock);
+	SLIST_REMOVE(&vp->v_pollinfo->vpi_selinfo.si_note,
+	    kn, knote, kn_selnext);
+	mtx_unlock(&vp->v_pollinfo->vpi_lock);
+}
+
+/*ARGSUSED*/
+static int
+filt_ext2read(struct knote *kn, long hint)
+{
+	struct vnode *vp = (struct vnode *)kn->kn_hook;
+	struct inode *ip = VTOI(vp);
+
+	/*
+	 * filesystem is gone, so set the EOF flag and schedule 
+	 * the knote for deletion.
+	 */
+	if (hint == NOTE_REVOKE) {
+		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
+		return (1);
+	}
+
+        kn->kn_data = ip->i_size - kn->kn_fp->f_offset;
+        return (kn->kn_data != 0);
+}
+
+/*ARGSUSED*/
+static int
+filt_ext2write(struct knote *kn, long hint)
+{
+
+	/*
+	 * filesystem is gone, so set the EOF flag and schedule 
+	 * the knote for deletion.
+	 */
+	if (hint == NOTE_REVOKE)
+		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
+
+        kn->kn_data = 0;
+        return (1);
+}
+
+static int
+filt_ext2vnode(struct knote *kn, long hint)
+{
+
+	if (kn->kn_sfflags & hint)
+		kn->kn_fflags |= hint;
+	if (hint == NOTE_REVOKE) {
+		kn->kn_flags |= EV_EOF;
+		return (1);
+	}
+	return (kn->kn_fflags != 0);
+}
diff --git a/sys/gnu/fs/ext2fs/fs.h b/sys/gnu/fs/ext2fs/fs.h
index 785f267f8ac3..50fb711f371f 100644
--- a/sys/gnu/fs/ext2fs/fs.h
+++ b/sys/gnu/fs/ext2fs/fs.h
@@ -148,7 +148,7 @@ extern u_char *fragtbl[];
  * I haven't figured out yet what BSD does
  * I think I'll try a VOP_LOCK/VOP_UNLOCK on the device vnode
  */
-#define  DEVVP(inode)		(VFSTOUFS(ITOV(inode)->v_mount)->um_devvp)
+#define  DEVVP(inode)		(VFSTOEXT2(ITOV(inode)->v_mount)->um_devvp)
 #define  lock_super(devvp)   	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, curthread)
 #define  unlock_super(devvp) 	VOP_UNLOCK(devvp, 0, curthread)
 
diff --git a/sys/modules/ext2fs/Makefile b/sys/modules/ext2fs/Makefile
index 9de1d6c5e948..b746452d5baa 100644
--- a/sys/modules/ext2fs/Makefile
+++ b/sys/modules/ext2fs/Makefile
@@ -3,8 +3,8 @@
 .PATH:	${.CURDIR}/../../gnu/ext2fs
 KMOD=	ext2fs
 SRCS=	opt_ddb.h opt_quota.h opt_suiddir.h vnode_if.h \
-	ext2_alloc.c ext2_balloc.c ext2_inode.c ext2_inode_cnv.c \
-	ext2_linux_balloc.c ext2_linux_ialloc.c ext2_lookup.c ext2_subr.c \
-	ext2_vfsops.c ext2_vnops.c
+	ext2_alloc.c ext2_balloc.c ext2_bmap.c ext2_ihash.c ext2_inode.c \
+	ext2_inode_cnv.c ext2_linux_balloc.c ext2_linux_ialloc.c \
+	ext2_lookup.c ext2_subr.c ext2_vfsops.c ext2_vnops.c
 
 .include <bsd.kmod.mk>