[Midnightbsd-cvs] src [10028] trunk/sys/fs: sync with freebsd

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun May 27 18:19:26 EDT 2018


Revision: 10028
          http://svnweb.midnightbsd.org/src/?rev=10028
Author:   laffer1
Date:     2018-05-27 18:19:26 -0400 (Sun, 27 May 2018)
Log Message:
-----------
sync with freebsd

Modified Paths:
--------------
    trunk/sys/fs/cd9660/TODO
    trunk/sys/fs/cd9660/TODO.hibler
    trunk/sys/fs/cd9660/cd9660_bmap.c
    trunk/sys/fs/cd9660/cd9660_iconv.c
    trunk/sys/fs/cd9660/cd9660_lookup.c
    trunk/sys/fs/cd9660/cd9660_mount.h
    trunk/sys/fs/cd9660/cd9660_node.c
    trunk/sys/fs/cd9660/cd9660_node.h
    trunk/sys/fs/cd9660/cd9660_rrip.c
    trunk/sys/fs/cd9660/cd9660_rrip.h
    trunk/sys/fs/cd9660/cd9660_util.c
    trunk/sys/fs/cd9660/cd9660_vfsops.c
    trunk/sys/fs/cd9660/cd9660_vnops.c
    trunk/sys/fs/cd9660/iso.h
    trunk/sys/fs/cd9660/iso_rrip.h
    trunk/sys/fs/deadfs/dead_vnops.c
    trunk/sys/fs/devfs/devfs.h
    trunk/sys/fs/devfs/devfs_devs.c
    trunk/sys/fs/devfs/devfs_dir.c
    trunk/sys/fs/devfs/devfs_int.h
    trunk/sys/fs/devfs/devfs_rule.c
    trunk/sys/fs/devfs/devfs_vfsops.c
    trunk/sys/fs/devfs/devfs_vnops.c
    trunk/sys/fs/ext2fs/ext2_alloc.c
    trunk/sys/fs/ext2fs/ext2_balloc.c
    trunk/sys/fs/ext2fs/ext2_bmap.c
    trunk/sys/fs/ext2fs/ext2_dinode.h
    trunk/sys/fs/ext2fs/ext2_dir.h
    trunk/sys/fs/ext2fs/ext2_extern.h
    trunk/sys/fs/ext2fs/ext2_inode.c
    trunk/sys/fs/ext2fs/ext2_inode_cnv.c
    trunk/sys/fs/ext2fs/ext2_lookup.c
    trunk/sys/fs/ext2fs/ext2_mount.h
    trunk/sys/fs/ext2fs/ext2_subr.c
    trunk/sys/fs/ext2fs/ext2_vfsops.c
    trunk/sys/fs/ext2fs/ext2_vnops.c
    trunk/sys/fs/ext2fs/ext2fs.h
    trunk/sys/fs/ext2fs/fs.h
    trunk/sys/fs/ext2fs/inode.h
    trunk/sys/fs/fdescfs/fdesc.h
    trunk/sys/fs/fdescfs/fdesc_vfsops.c
    trunk/sys/fs/fdescfs/fdesc_vnops.c
    trunk/sys/fs/fifofs/fifo_vnops.c
    trunk/sys/fs/msdosfs/bootsect.h
    trunk/sys/fs/msdosfs/bpb.h
    trunk/sys/fs/msdosfs/denode.h
    trunk/sys/fs/msdosfs/direntry.h
    trunk/sys/fs/msdosfs/fat.h
    trunk/sys/fs/msdosfs/msdosfs_conv.c
    trunk/sys/fs/msdosfs/msdosfs_denode.c
    trunk/sys/fs/msdosfs/msdosfs_fat.c
    trunk/sys/fs/msdosfs/msdosfs_fileno.c
    trunk/sys/fs/msdosfs/msdosfs_iconv.c
    trunk/sys/fs/msdosfs/msdosfs_lookup.c
    trunk/sys/fs/msdosfs/msdosfs_vfsops.c
    trunk/sys/fs/msdosfs/msdosfs_vnops.c
    trunk/sys/fs/msdosfs/msdosfsmount.h

Added Paths:
-----------
    trunk/sys/fs/ext2fs/ext2_extents.c
    trunk/sys/fs/ext2fs/ext2_extents.h
    trunk/sys/fs/ext2fs/ext2_hash.c
    trunk/sys/fs/ext2fs/ext2_htree.c
    trunk/sys/fs/ext2fs/htree.h

Property Changed:
----------------
    trunk/sys/fs/cd9660/TODO
    trunk/sys/fs/cd9660/TODO.hibler

Modified: trunk/sys/fs/cd9660/TODO
===================================================================
--- trunk/sys/fs/cd9660/TODO	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/TODO	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,4 @@
-# $MidnightBSD$
+# $FreeBSD: stable/10/sys/fs/cd9660/TODO 166639 2007-02-11 13:54:25Z rodrigc $
 
  2) should understand Rock Ridge
 


Property changes on: trunk/sys/fs/cd9660/TODO
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/fs/cd9660/TODO.hibler
===================================================================
--- trunk/sys/fs/cd9660/TODO.hibler	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/TODO.hibler	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,4 @@
-$MidnightBSD$
+$FreeBSD: stable/10/sys/fs/cd9660/TODO.hibler 166639 2007-02-11 13:54:25Z rodrigc $
 
 1. Investiate making ISOFS another UFS shared filesystem (ala FFS/MFS/LFS).
    Since it was modelled after the inode code, we might be able to merge


Property changes on: trunk/sys/fs/cd9660/TODO.hibler
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/sys/fs/cd9660/cd9660_bmap.c
===================================================================
--- trunk/sys/fs/cd9660/cd9660_bmap.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/cd9660_bmap.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1994
  *	The Regents of the University of California.  All rights reserved.
@@ -35,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/fs/cd9660/cd9660_bmap.c 185071 2008-11-18 23:19:43Z jhb $");
 
 #include <sys/param.h>
 #include <sys/systm.h>

Modified: trunk/sys/fs/cd9660/cd9660_iconv.c
===================================================================
--- trunk/sys/fs/cd9660/cd9660_iconv.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/cd9660_iconv.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003 Ryuichiro Imura
  * All rights reserved.
@@ -25,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/fs/cd9660/cd9660_iconv.c 166639 2007-02-11 13:54:25Z rodrigc $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>

Modified: trunk/sys/fs/cd9660/cd9660_lookup.c
===================================================================
--- trunk/sys/fs/cd9660/cd9660_lookup.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/cd9660_lookup.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1989, 1993, 1994
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/fs/cd9660/cd9660_lookup.c 269165 2014-07-28 00:53:26Z kib $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -50,6 +51,23 @@
 #include <fs/cd9660/cd9660_node.h>
 #include <fs/cd9660/iso_rrip.h>
 
+struct cd9660_ino_alloc_arg {
+	ino_t ino;
+	ino_t i_ino;
+	struct iso_directory_record *ep;
+};
+
+static int
+cd9660_ino_alloc(struct mount *mp, void *arg, int lkflags,
+    struct vnode **vpp)
+{
+	struct cd9660_ino_alloc_arg *dd_arg;
+
+	dd_arg = arg;
+	return (cd9660_vget_internal(mp, dd_arg->i_ino, lkflags, vpp,
+	    dd_arg->i_ino != dd_arg->ino, dd_arg->ep));
+}
+
 /*
  * Convert a component of a pathname into a pointer to a locked inode.
  * This is a very central and rather complicated routine.
@@ -104,6 +122,7 @@
 	doff_t endsearch;		/* offset to end directory search */
 	struct vnode *pdp;		/* saved dp during symlink work */
 	struct vnode *tdp;		/* returned by cd9660_vget_internal */
+	struct cd9660_ino_alloc_arg dd_arg;
 	u_long bmask;			/* block offset mask */
 	int error;
 	ino_t ino, i_ino;
@@ -114,7 +133,6 @@
 	int res;
 	int assoc, len;
 	char *name;
-	struct mount *mp;
 	struct vnode **vpp = ap->a_vpp;
 	struct componentname *cnp = ap->a_cnp;
 	int flags = cnp->cn_flags;
@@ -368,39 +386,13 @@
 	 * it's a relocated directory.
 	 */
 	if (flags & ISDOTDOT) {
-		/*
-		 * Expanded copy of vn_vget_ino() so that we can use
-		 * cd9660_vget_internal().
-		 */
-		mp = pdp->v_mount;
-		ltype = VOP_ISLOCKED(pdp);
-		error = vfs_busy(mp, MBF_NOWAIT);
-		if (error != 0) {
-			vfs_ref(mp);
-			VOP_UNLOCK(pdp, 0);
-			error = vfs_busy(mp, 0);
-			vn_lock(pdp, ltype | LK_RETRY);
-			vfs_rel(mp);
-			if (error)
-				return (ENOENT);
-			if (pdp->v_iflag & VI_DOOMED) {
-				vfs_unbusy(mp);
-				return (ENOENT);
-			}
-		}
-		VOP_UNLOCK(pdp, 0);
-		error = cd9660_vget_internal(vdp->v_mount, i_ino,
-					     cnp->cn_lkflags, &tdp,
-					     i_ino != ino, ep);
+		dd_arg.ino = ino;
+		dd_arg.i_ino = i_ino;
+		dd_arg.ep = ep;
+		error = vn_vget_ino_gen(pdp, cd9660_ino_alloc, &dd_arg,
+		    cnp->cn_lkflags, &tdp);
 		free(ep2, M_TEMP);
-		vfs_unbusy(mp);
-		vn_lock(pdp, ltype | LK_RETRY);
-		if (pdp->v_iflag & VI_DOOMED) {
-			if (error == 0)
-				vput(tdp);
-			error = ENOENT;
-		}
-		if (error)
+		if (error != 0)
 			return (error);
 		*vpp = tdp;
 	} else if (dp->i_number == i_ino) {

Modified: trunk/sys/fs/cd9660/cd9660_mount.h
===================================================================
--- trunk/sys/fs/cd9660/cd9660_mount.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/cd9660_mount.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1995
  *	The Regents of the University of California.  All rights reserved.
@@ -32,7 +33,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)cd9660_mount.h	8.1 (Berkeley) 5/24/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/cd9660/cd9660_mount.h 213664 2010-10-10 07:05:47Z kib $
  */
 
 /*

Modified: trunk/sys/fs/cd9660/cd9660_node.c
===================================================================
--- trunk/sys/fs/cd9660/cd9660_node.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/cd9660_node.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1982, 1986, 1989, 1994, 1995
  *	The Regents of the University of California.  All rights reserved.
@@ -35,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/fs/cd9660/cd9660_node.c 234607 2012-04-23 14:10:34Z trasz $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -65,7 +66,6 @@
 	} */ *ap;
 {
 	struct vnode *vp = ap->a_vp;
-	struct thread *td = ap->a_td;
 	struct iso_node *ip = VTOI(vp);
 	int error = 0;
 
@@ -74,7 +74,7 @@
 	 * so that it can be reused immediately.
 	 */
 	if (ip->inode.iso_mode == 0)
-		vrecycle(vp, td);
+		vrecycle(vp);
 	return error;
 }
 

Modified: trunk/sys/fs/cd9660/cd9660_node.h
===================================================================
--- trunk/sys/fs/cd9660/cd9660_node.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/cd9660_node.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1994
  *	The Regents of the University of California.  All rights reserved.
@@ -32,7 +33,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)cd9660_node.h	8.6 (Berkeley) 5/14/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/cd9660/cd9660_node.h 187838 2009-01-28 18:54:56Z jhb $
  */
 
 /*

Modified: trunk/sys/fs/cd9660/cd9660_rrip.c
===================================================================
--- trunk/sys/fs/cd9660/cd9660_rrip.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/cd9660_rrip.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1993, 1994
  *	The Regents of the University of California.  All rights reserved.
@@ -35,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/fs/cd9660/cd9660_rrip.c 193066 2009-05-29 21:27:12Z jamie $");
 
 #include <sys/param.h>
 #include <sys/systm.h>

Modified: trunk/sys/fs/cd9660/cd9660_rrip.h
===================================================================
--- trunk/sys/fs/cd9660/cd9660_rrip.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/cd9660_rrip.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1993, 1994
  *	The Regents of the University of California.  All rights reserved.
@@ -32,7 +33,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)cd9660_rrip.h	8.2 (Berkeley) 12/5/94
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/cd9660/cd9660_rrip.h 166639 2007-02-11 13:54:25Z rodrigc $
  */
 
 typedef struct {

Modified: trunk/sys/fs/cd9660/cd9660_util.c
===================================================================
--- trunk/sys/fs/cd9660/cd9660_util.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/cd9660_util.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1994
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/fs/cd9660/cd9660_util.c 278060 2015-02-02 07:42:03Z dim $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -80,7 +81,8 @@
               inbuf[2]='\0';
               inp = inbuf;
               outp = outbuf;
-              cd9660_iconv->convchr(handle, (const char **)&inp, &i, &outp, &j);
+              cd9660_iconv->convchr(handle, __DECONST(const char **, &inp), &i,
+                  &outp, &j);
               len -= j;
               if (clen) *clen = len;
               *c = '\0';
@@ -121,7 +123,8 @@
 	u_char *fnend = fn + fnlen, *isoend = isofn + isolen;
 
 	for (; fn < fnend; ) {
-		d = sgetrune(fn, fnend - fn, (char const **)&fn, flags, lhandle);
+		d = sgetrune(fn, fnend - fn, __DECONST(const char **, &fn),
+		    flags, lhandle);
 		if (isofn == isoend)
 			return d;
 		isofn += isochar(isofn, isoend, joliet_level, &c, NULL, flags, handle);

Modified: trunk/sys/fs/cd9660/cd9660_vfsops.c
===================================================================
--- trunk/sys/fs/cd9660/cd9660_vfsops.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/cd9660_vfsops.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1994
  *	The Regents of the University of California.  All rights reserved.
@@ -35,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/fs/cd9660/cd9660_vfsops.c 255867 2013-09-25 02:49:18Z jmg $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -133,7 +134,7 @@
 	int error;
 	accmode_t accmode;
 	struct nameidata ndp;
-	struct iso_mnt *imp = 0;
+	struct iso_mnt *imp = NULL;
 
 	td = curthread;
 
@@ -205,7 +206,7 @@
 	struct vnode *devvp;
 	struct mount *mp;
 {
-	struct iso_mnt *isomp = (struct iso_mnt *)0;
+	struct iso_mnt *isomp = NULL;
 	struct buf *bp = NULL;
 	struct buf *pribp = NULL, *supbp = NULL;
 	struct cdev *dev;
@@ -214,7 +215,7 @@
 	int iso_bsize;
 	int iso_blknum;
 	int joliet_level;
-	struct iso_volume_descriptor *vdp = 0;
+	struct iso_volume_descriptor *vdp = NULL;
 	struct iso_primary_descriptor *pri = NULL;
 	struct iso_sierra_primary_descriptor *pri_sierra = NULL;
 	struct iso_supplementary_descriptor *sup = NULL;
@@ -369,6 +370,9 @@
 	pribp->b_flags |= B_AGE;
 	brelse(pribp);
 	pribp = NULL;
+	rootp = NULL;
+	pri = NULL;
+	pri_sierra = NULL;
 
 	mp->mnt_data = isomp;
 	mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
@@ -376,8 +380,7 @@
 	mp->mnt_maxsymlinklen = 0;
 	MNT_ILOCK(mp);
 	mp->mnt_flag |= MNT_LOCAL;
-	mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED |
-	    MNTK_EXTENDED_SHARED;
+	mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED;
 	MNT_IUNLOCK(mp);
 	isomp->im_mountp = mp;
 	isomp->im_dev = dev;
@@ -391,11 +394,11 @@
 
 	/* Check the Rock Ridge Extension support */
 	if (!(isomp->im_flags & ISOFSMNT_NORRIP)) {
-		if ((error = bread(isomp->im_devvp,
-				  (isomp->root_extent + isonum_711(rootp->ext_attr_length)) <<
-				  (isomp->im_bshift - DEV_BSHIFT),
-				  isomp->logical_block_size, NOCRED, &bp)) != 0)
-		    goto out;
+		if ((error = bread(isomp->im_devvp, (isomp->root_extent +
+		    isonum_711(((struct iso_directory_record *)isomp->root)->
+		    ext_attr_length)) << (isomp->im_bshift - DEV_BSHIFT),
+		    isomp->logical_block_size, NOCRED, &bp)) != 0)
+			goto out;
 
 		rootp = (struct iso_directory_record *)bp->b_data;
 
@@ -412,6 +415,7 @@
 		bp->b_flags |= B_AGE;
 		brelse(bp);
 		bp = NULL;
+		rootp = NULL;
 	}
 
 	if (isomp->im_flags & ISOFSMNT_KICONV && cd9660_iconv) {
@@ -466,6 +470,7 @@
 	if (supbp) {
 		brelse(supbp);
 		supbp = NULL;
+		sup = NULL;
 	}
 
 	return 0;
@@ -484,7 +489,7 @@
 		PICKUP_GIANT();
 	}
 	if (isomp) {
-		free((caddr_t)isomp, M_ISOFSMNT);
+		free(isomp, M_ISOFSMNT);
 		mp->mnt_data = NULL;
 	}
 	dev_rel(dev);
@@ -522,7 +527,7 @@
 	PICKUP_GIANT();
 	vrele(isomp->im_devvp);
 	dev_rel(isomp->im_dev);
-	free((caddr_t)isomp, M_ISOFSMNT);
+	free(isomp, M_ISOFSMNT);
 	mp->mnt_data = NULL;
 	MNT_ILOCK(mp);
 	mp->mnt_flag &= ~MNT_LOCAL;

Modified: trunk/sys/fs/cd9660/cd9660_vnops.c
===================================================================
--- trunk/sys/fs/cd9660/cd9660_vnops.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/cd9660_vnops.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1994
  *	The Regents of the University of California.  All rights reserved.
@@ -35,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/fs/cd9660/cd9660_vnops.c 248282 2013-03-14 20:28:26Z kib $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -47,7 +48,6 @@
 #include <sys/buf.h>
 #include <sys/mount.h>
 #include <sys/vnode.h>
-#include <fs/fifofs/fifo.h>
 #include <sys/malloc.h>
 #include <sys/dirent.h>
 #include <sys/unistd.h>
@@ -330,7 +330,7 @@
 			if (lblktosize(imp, rablock) < ip->i_size)
 				error = cluster_read(vp, (off_t)ip->i_size,
 					 lbn, size, NOCRED, uio->uio_resid,
-					 (ap->a_ioflag >> 16), &bp);
+					 (ap->a_ioflag >> 16), 0, &bp);
 			else
 				error = bread(vp, lbn, size, NOCRED, &bp);
 		} else {

Modified: trunk/sys/fs/cd9660/iso.h
===================================================================
--- trunk/sys/fs/cd9660/iso.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/iso.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1994
  *	The Regents of the University of California.  All rights reserved.
@@ -32,7 +33,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)iso.h	8.6 (Berkeley) 5/10/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/cd9660/iso.h 253742 2013-07-28 12:29:10Z marius $
  */
 
 #define ISODCL(from, to) (to - from + 1)
@@ -291,56 +292,65 @@
  */
 
 static __inline uint8_t
-isonum_711(unsigned char *p)
+isonum_711(const unsigned char *p)
 {
-	return p[0];
+
+	return (p[0]);
 }
 
-static __inline uint8_t
-isonum_712(unsigned char *p)
+static __inline int8_t
+isonum_712(const unsigned char *p)
 {
-	return p[0];
+
+	return ((signed char)p[0]);
 }
 
 static __inline uint8_t
-isonum_713(unsigned char *p)
+isonum_713(const unsigned char *p)
 {
-	return p[0];
+
+	return (p[0]);
 }
 
 static __inline uint16_t
-isonum_721(unsigned char *p)
+isonum_721(const unsigned char *p)
 {
+
 	return (p[0] | p[1] << 8);
 }
 
 static __inline uint16_t
-isonum_722(unsigned char *p)
+isonum_722(const unsigned char *p)
 {
+
 	return (p[1] | p[0] << 8);
 }
 
 static __inline uint16_t
-isonum_723(unsigned char *p)
+isonum_723(const unsigned char *p)
 {
+
 	return (p[0] | p[1] << 8);
 }
 
 static __inline uint32_t
-isonum_731(unsigned char *p)
+isonum_731(const unsigned char *p)
 {
+
 	return (p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24);
 }
 
 static __inline uint32_t
-isonum_732(unsigned char *p)
+isonum_732(const unsigned char *p)
 {
+
 	return (p[3] | p[2] << 8 | p[1] << 16 | p[0] << 24);
 }
 
 static __inline uint32_t
-isonum_733(unsigned char *p)
+isonum_733(const unsigned char *p)
 {
+
 	return (p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24);
 }
 

Modified: trunk/sys/fs/cd9660/iso_rrip.h
===================================================================
--- trunk/sys/fs/cd9660/iso_rrip.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/cd9660/iso_rrip.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1993, 1994
  *	The Regents of the University of California.  All rights reserved.
@@ -32,7 +33,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)iso_rrip.h	8.2 (Berkeley) 1/23/94
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/cd9660/iso_rrip.h 166639 2007-02-11 13:54:25Z rodrigc $
  */
 
 

Modified: trunk/sys/fs/deadfs/dead_vnops.c
===================================================================
--- trunk/sys/fs/deadfs/dead_vnops.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/deadfs/dead_vnops.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -27,7 +28,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)dead_vnops.c	8.1 (Berkeley) 6/10/93
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/deadfs/dead_vnops.c 273463 2014-10-22 09:12:20Z kib $
  */
 
 #include <sys/param.h>
@@ -43,9 +44,6 @@
  */
 static vop_lookup_t	dead_lookup;
 static vop_open_t	dead_open;
-static vop_poll_t	dead_poll;
-static vop_read_t	dead_read;
-static vop_write_t	dead_write;
 static vop_getwritemount_t dead_getwritemount;
 static vop_rename_t	dead_rename;
 
@@ -80,14 +78,10 @@
 	.vop_write =		dead_write,
 };
 
-/* ARGSUSED */
 static int
-dead_getwritemount(ap)
-	struct vop_getwritemount_args /* {
-		struct vnode *a_vp;
-		struct mount **a_mpp;
-	} */ *ap;
+dead_getwritemount(struct vop_getwritemount_args *ap)
 {
+
 	*(ap->a_mpp) = NULL;
 	return (0);
 }
@@ -95,14 +89,8 @@
 /*
  * Trivial lookup routine that always fails.
  */
-/* ARGSUSED */
 static int
-dead_lookup(ap)
-	struct vop_lookup_args /* {
-		struct vnode * a_dvp;
-		struct vnode ** a_vpp;
-		struct componentname * a_cnp;
-	} */ *ap;
+dead_lookup(struct vop_lookup_args *ap)
 {
 
 	*ap->a_vpp = NULL;
@@ -112,33 +100,17 @@
 /*
  * Open always fails as if device did not exist.
  */
-/* ARGSUSED */
 static int
-dead_open(ap)
-	struct vop_open_args /* {
-		struct vnode *a_vp;
-		int  a_mode;
-		struct ucred *a_cred;
-		struct proc *a_p;
-	} */ *ap;
+dead_open(struct vop_open_args *ap)
 {
 
 	return (ENXIO);
 }
 
-/*
- * Vnode op for read
- */
-/* ARGSUSED */
-static int
-dead_read(ap)
-	struct vop_read_args /* {
-		struct vnode *a_vp;
-		struct uio *a_uio;
-		int  a_ioflag;
-		struct ucred *a_cred;
-	} */ *ap;
+int
+dead_read(struct vop_read_args *ap)
 {
+
 	/*
 	 * Return EOF for tty devices, EIO for others
 	 */
@@ -147,44 +119,29 @@
 	return (0);
 }
 
-/*
- * Vnode op for write
- */
-/* ARGSUSED */
-static int
-dead_write(ap)
-	struct vop_write_args /* {
-		struct vnode *a_vp;
-		struct uio *a_uio;
-		int  a_ioflag;
-		struct ucred *a_cred;
-	} */ *ap;
+int
+dead_write(struct vop_write_args *ap)
 {
+
 	return (EIO);
 }
 
-/*
- * Trivial poll routine that always returns POLLHUP.
- * This is necessary so that a process which is polling a file
- * gets notified when that file is revoke()d.
- */
-static int
-dead_poll(ap)
-	struct vop_poll_args *ap;
+int
+dead_poll(struct vop_poll_args *ap)
 {
-	return (POLLHUP);
+
+	if (ap->a_events & ~POLLSTANDARD)
+		return (POLLNVAL);
+
+	/*
+	 * Let the user find out that the descriptor is gone.
+	 */
+	return (POLLHUP | ((POLLIN | POLLRDNORM) & ap->a_events));
+
 }
 
 static int
-dead_rename(ap)
-	struct vop_rename_args  /* {
-		struct vnode *a_fdvp;
-		struct vnode *a_fvp;
-		struct componentname *a_fcnp;
-		struct vnode *a_tdvp;
-		struct vnode *a_tvp;
-		struct componentname *a_tcnp;
-	} */ *ap;
+dead_rename(struct vop_rename_args *ap)
 {
 
 	vop_rename_fail(ap);

Modified: trunk/sys/fs/devfs/devfs.h
===================================================================
--- trunk/sys/fs/devfs/devfs.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/devfs/devfs.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1992, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -33,7 +34,7 @@
  *	@(#)kernfs.h	8.6 (Berkeley) 3/29/95
  * From: FreeBSD: src/sys/miscfs/kernfs/kernfs.h 1.14
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/devfs/devfs.h 231265 2012-02-09 10:09:12Z mm $
  */
 
 #ifndef _FS_DEVFS_DEVFS_H_

Modified: trunk/sys/fs/devfs/devfs_devs.c
===================================================================
--- trunk/sys/fs/devfs/devfs_devs.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/devfs/devfs_devs.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2000,2004
  *	Poul-Henning Kamp.  All rights reserved.
@@ -25,7 +26,7 @@
  *
  * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/devfs/devfs_devs.c 313932 2017-02-19 03:17:11Z kib $
  */
 
 #include <sys/param.h>
@@ -61,7 +62,7 @@
 static MALLOC_DEFINE(M_DEVFS3, "DEVFS3", "DEVFS data 3");
 static MALLOC_DEFINE(M_CDEVP, "DEVFS1", "DEVFS cdev_priv storage");
 
-static SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, "DEVFS filesystem");
+SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, "DEVFS filesystem");
 
 static unsigned devfs_generation;
 SYSCTL_UINT(_vfs_devfs, OID_AUTO, generation, CTLFLAG_RD,
@@ -109,10 +110,10 @@
     NULL, 0, sysctl_devname, "", "devname(3) handler");
 
 SYSCTL_INT(_debug_sizeof, OID_AUTO, cdev, CTLFLAG_RD,
-    0, sizeof(struct cdev), "sizeof(struct cdev)");
+    SYSCTL_NULL_INT_PTR, sizeof(struct cdev), "sizeof(struct cdev)");
 
 SYSCTL_INT(_debug_sizeof, OID_AUTO, cdev_priv, CTLFLAG_RD,
-    0, sizeof(struct cdev_priv), "sizeof(struct cdev_priv)");
+    SYSCTL_NULL_INT_PTR, sizeof(struct cdev_priv), "sizeof(struct cdev_priv)");
 
 struct cdev *
 devfs_alloc(int flags)
@@ -121,23 +122,17 @@
 	struct cdev *cdev;
 	struct timespec ts;
 
-	cdp = malloc(sizeof *cdp, M_CDEVP, M_USE_RESERVE | M_ZERO |
+	cdp = malloc(sizeof *cdp, M_CDEVP, M_ZERO |
 	    ((flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK));
 	if (cdp == NULL)
 		return (NULL);
 
 	cdp->cdp_dirents = &cdp->cdp_dirent0;
-	cdp->cdp_dirent0 = NULL;
-	cdp->cdp_maxdirent = 0;
-	cdp->cdp_inode = 0;
 
 	cdev = &cdp->cdp_c;
-
-	cdev->si_name = cdev->__si_namebuf;
 	LIST_INIT(&cdev->si_children);
 	vfs_timestamp(&ts);
 	cdev->si_atime = cdev->si_mtime = cdev->si_ctime = ts;
-	cdev->si_cred = NULL;
 
 	return (cdev);
 }
@@ -187,6 +182,16 @@
 			continue;
 		if (type != 0 && type != de->de_dirent->d_type)
 			continue;
+
+		/*
+		 * The race with finding non-active name is not
+		 * completely closed by the check, but it is similar
+		 * to the devfs_allocv() in making it unlikely enough.
+		 */
+		if (de->de_dirent->d_type == DT_CHR &&
+		    (de->de_cdp->cdp_flags & CDP_ACTIVE) == 0)
+			continue;
+
 		if (bcmp(name, de->de_dirent->d_name, namelen) != 0)
 			continue;
 		break;
@@ -204,7 +209,7 @@
 	struct dirent d;
 
 	d.d_namlen = namelen;
-	i = sizeof (*de) + GENERIC_DIRSIZ(&d); 
+	i = sizeof(*de) + GENERIC_DIRSIZ(&d);
 	de = malloc(i, M_DEVFS3, M_WAITOK | M_ZERO);
 	de->de_dirent = (struct dirent *)(de + 1);
 	de->de_dirent->d_namlen = namelen;
@@ -242,7 +247,8 @@
 }
 
 struct devfs_dirent *
-devfs_vmkdir(struct devfs_mount *dmp, char *name, int namelen, struct devfs_dirent *dotdot, u_int inode)
+devfs_vmkdir(struct devfs_mount *dmp, char *name, int namelen,
+    struct devfs_dirent *dotdot, u_int inode)
 {
 	struct devfs_dirent *dd;
 	struct devfs_dirent *de;
@@ -295,6 +301,13 @@
 void
 devfs_dirent_free(struct devfs_dirent *de)
 {
+	struct vnode *vp;
+
+	vp = de->de_vnode;
+	mtx_lock(&devfs_de_interlock);
+	if (vp != NULL && vp->v_data == de)
+		vp->v_data = NULL;
+	mtx_unlock(&devfs_de_interlock);
 	free(de, M_DEVFS3);
 }
 
@@ -656,7 +669,7 @@
 /*
  * devfs_create() and devfs_destroy() are called from kern_conf.c and
  * in both cases the devlock() mutex is held, so no further locking
- * is necesary and no sleeping allowed.
+ * is necessary and no sleeping allowed.
  */
 
 void

Modified: trunk/sys/fs/devfs/devfs_dir.c
===================================================================
--- trunk/sys/fs/devfs/devfs_dir.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/devfs/devfs_dir.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2010 Jaakko Heinonen <jh at FreeBSD.org>
  * All rights reserved.
@@ -23,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/devfs/devfs_dir.c 213215 2010-09-27 17:47:09Z jh $
  */
 
 #include <sys/param.h>

Modified: trunk/sys/fs/devfs/devfs_int.h
===================================================================
--- trunk/sys/fs/devfs/devfs_int.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/devfs/devfs_int.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005 Poul-Henning Kamp.  All rights reserved.
  *
@@ -22,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/devfs/devfs_int.h 278283 2015-02-05 20:49:13Z hselasky $
  */
 
 /*
@@ -70,7 +71,7 @@
 	LIST_HEAD(, cdev_privdata) cdp_fdpriv;
 };
 
-#define	cdev2priv(c)	member2struct(cdev_priv, cdp_c, c)
+#define	cdev2priv(c)	__containerof(c, struct cdev_priv, cdp_c)
 
 struct cdev	*devfs_alloc(int);
 int	devfs_dev_exists(const char *);

Modified: trunk/sys/fs/devfs/devfs_rule.c
===================================================================
--- trunk/sys/fs/devfs/devfs_rule.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/devfs/devfs_rule.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2002 Dima Dorfman.
  * All rights reserved.
@@ -23,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/devfs/devfs_rule.c 253677 2013-07-26 14:25:58Z avg $
  */
 
 /*
@@ -101,7 +102,7 @@
 static devfs_rid devfs_rid_input(devfs_rid rid, struct devfs_mount *dm);
 
 static void devfs_rule_applyde_recursive(struct devfs_krule *dk,
-		struct devfs_dirent *de);
+		struct devfs_mount *dm, struct devfs_dirent *de);
 static void devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm);
 static int  devfs_rule_autonumber(struct devfs_ruleset *ds, devfs_rnum *rnp);
 static struct devfs_krule *devfs_rule_byid(devfs_rid rid);
@@ -109,13 +110,16 @@
 static struct cdev *devfs_rule_getdev(struct devfs_dirent *de);
 static int  devfs_rule_input(struct devfs_rule *dr, struct devfs_mount *dm);
 static int  devfs_rule_insert(struct devfs_rule *dr);
-static int  devfs_rule_match(struct devfs_krule *dk, struct devfs_dirent *de);
-static int  devfs_rule_matchpath(struct devfs_krule *dk,
+static int  devfs_rule_match(struct devfs_krule *dk, struct devfs_mount *dm,
 		struct devfs_dirent *de);
-static void devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de, unsigned depth);
+static int  devfs_rule_matchpath(struct devfs_krule *dk, struct devfs_mount *dm,
+		struct devfs_dirent *de);
+static void devfs_rule_run(struct devfs_krule *dk, struct devfs_mount *dm,
+		struct devfs_dirent *de, unsigned depth);
 
 static void devfs_ruleset_applyde(struct devfs_ruleset *ds,
-		struct devfs_dirent *de, unsigned depth);
+		struct devfs_mount *dm, struct devfs_dirent *de,
+		unsigned depth);
 static void devfs_ruleset_applydm(struct devfs_ruleset *ds,
 		struct devfs_mount *dm);
 static struct devfs_ruleset *devfs_ruleset_bynum(devfs_rsnum rsnum);
@@ -146,7 +150,7 @@
 	sx_slock(&sx_rules);
 	ds = devfs_ruleset_bynum(dm->dm_ruleset);
 	KASSERT(ds != NULL, ("mount-point has NULL ruleset"));
-	devfs_ruleset_applyde(ds, de, devfs_rule_depth);
+	devfs_ruleset_applyde(ds, dm, de, devfs_rule_depth);
 	sx_sunlock(&sx_rules);
 }
 
@@ -337,13 +341,14 @@
  * XXX: a linear search could be done through the cdev list instead.
  */
 static void
-devfs_rule_applyde_recursive(struct devfs_krule *dk, struct devfs_dirent *de)
+devfs_rule_applyde_recursive(struct devfs_krule *dk, struct devfs_mount *dm,
+    struct devfs_dirent *de)
 {
 	struct devfs_dirent *de2;
 
 	TAILQ_FOREACH(de2, &de->de_dlist, de_list)
-		devfs_rule_applyde_recursive(dk, de2);
-	devfs_rule_run(dk, de, devfs_rule_depth);
+		devfs_rule_applyde_recursive(dk, dm, de2);
+	devfs_rule_run(dk, dm, de, devfs_rule_depth);
 }
 
 /*
@@ -353,7 +358,7 @@
 devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm)
 {
 
-	devfs_rule_applyde_recursive(dk, dm->dm_rootdir);
+	devfs_rule_applyde_recursive(dk, dm, dm->dm_rootdir);
 }
 
 /*
@@ -525,7 +530,8 @@
  * de; 0, otherwise.
  */
 static int
-devfs_rule_match(struct devfs_krule *dk, struct devfs_dirent *de)
+devfs_rule_match(struct devfs_krule *dk, struct devfs_mount *dm,
+    struct devfs_dirent *de)
 {
 	struct devfs_rule *dr = &dk->dk_rule;
 	struct cdev *dev;
@@ -558,7 +564,7 @@
 		dev_relthread(dev, ref);
 	}
 	if (dr->dr_icond & DRC_PATHPTRN)
-		if (!devfs_rule_matchpath(dk, de))
+		if (!devfs_rule_matchpath(dk, dm, de))
 			return (0);
 
 	return (1);
@@ -568,23 +574,30 @@
  * Determine whether dk matches de on account of dr_pathptrn.
  */
 static int
-devfs_rule_matchpath(struct devfs_krule *dk, struct devfs_dirent *de)
+devfs_rule_matchpath(struct devfs_krule *dk, struct devfs_mount *dm,
+    struct devfs_dirent *de)
 {
 	struct devfs_rule *dr = &dk->dk_rule;
-	char *pname;
 	struct cdev *dev;
+	int match;
+	char *pname, *specname;
 
+	specname = NULL;
 	dev = devfs_rule_getdev(de);
 	if (dev != NULL)
 		pname = dev->si_name;
 	else if (de->de_dirent->d_type == DT_LNK ||
-	    de->de_dirent->d_type == DT_DIR)
-		pname = de->de_dirent->d_name;
-	else
+	    (de->de_dirent->d_type == DT_DIR && de != dm->dm_rootdir &&
+	    (de->de_flags & (DE_DOT | DE_DOTDOT)) == 0)) {
+		specname = malloc(SPECNAMELEN + 1, M_TEMP, M_WAITOK);
+		pname = devfs_fqpn(specname, dm, de, NULL);
+	} else
 		return (0);
+
 	KASSERT(pname != NULL, ("devfs_rule_matchpath: NULL pname"));
-
-	return (fnmatch(dr->dr_pathptrn, pname, 0) == 0);
+	match = fnmatch(dr->dr_pathptrn, pname, FNM_PATHNAME) == 0;
+	free(specname, M_TEMP);
+	return (match);
 }
 
 /*
@@ -591,12 +604,13 @@
  * Run dk on de.
  */
 static void
-devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de, unsigned depth)
+devfs_rule_run(struct devfs_krule *dk,  struct devfs_mount *dm,
+    struct devfs_dirent *de, unsigned depth)
 {
 	struct devfs_rule *dr = &dk->dk_rule;
 	struct devfs_ruleset *ds;
 
-	if (!devfs_rule_match(dk, de))
+	if (!devfs_rule_match(dk, dm, de))
 		return;
 	if (dr->dr_iacts & DRA_BACTS) {
 		if (dr->dr_bacts & DRB_HIDE)
@@ -623,7 +637,7 @@
 		if (depth > 0) {
 			ds = devfs_ruleset_bynum(dk->dk_rule.dr_incset);
 			KASSERT(ds != NULL, ("DRA_INCSET but bad dr_incset"));
-			devfs_ruleset_applyde(ds, de, depth - 1);
+			devfs_ruleset_applyde(ds, dm, de, depth - 1);
 		}
 	}
 }
@@ -632,12 +646,13 @@
  * Apply all the rules in ds to de.
  */
 static void
-devfs_ruleset_applyde(struct devfs_ruleset *ds, struct devfs_dirent *de, unsigned depth)
+devfs_ruleset_applyde(struct devfs_ruleset *ds, struct devfs_mount *dm,
+    struct devfs_dirent *de, unsigned depth)
 {
 	struct devfs_krule *dk;
 
 	TAILQ_FOREACH(dk, &ds->ds_rules, dk_list)
-		devfs_rule_run(dk, de, depth);
+		devfs_rule_run(dk, dm, de, depth);
 }
 
 /*

Modified: trunk/sys/fs/devfs/devfs_vfsops.c
===================================================================
--- trunk/sys/fs/devfs/devfs_vfsops.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/devfs/devfs_vfsops.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1992, 1993, 1995
  *	The Regents of the University of California.  All rights reserved.
@@ -31,7 +32,7 @@
  *	@(#)kernfs_vfsops.c	8.10 (Berkeley) 5/14/95
  * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/devfs/devfs_vfsops.c 297523 2016-04-03 14:38:02Z mav $
  */
 
 #include <sys/param.h>
@@ -131,8 +132,7 @@
 
 	MNT_ILOCK(mp);
 	mp->mnt_flag |= MNT_LOCAL;
-	mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED |
-	    MNTK_EXTENDED_SHARED;
+	mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED;
 #ifdef MAC
 	mp->mnt_flag |= MNT_MULTILABEL;
 #endif
@@ -183,6 +183,8 @@
 	fmp = VFSTODEVFS(mp);
 	KASSERT(fmp->dm_mount != NULL,
 		("devfs_unmount unmounted devfs_mount"));
+	if (mntflags & MNT_FORCE)
+		flags |= FORCECLOSE;
 	/* There is 1 extra root vnode reference from devfs_mount(). */
 	error = vflush(mp, 1, flags, curthread);
 	if (error)

Modified: trunk/sys/fs/devfs/devfs_vnops.c
===================================================================
--- trunk/sys/fs/devfs/devfs_vnops.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/devfs/devfs_vnops.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2000-2004
  *	Poul-Henning Kamp.  All rights reserved.
@@ -31,7 +32,7 @@
  *	@(#)kernfs_vnops.c	8.15 (Berkeley) 5/21/95
  * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/devfs/devfs_vnops.c 327060 2017-12-21 13:32:49Z kib $
  */
 
 /*
@@ -57,6 +58,7 @@
 #include <sys/proc.h>
 #include <sys/stat.h>
 #include <sys/sx.h>
+#include <sys/sysctl.h>
 #include <sys/time.h>
 #include <sys/ttycom.h>
 #include <sys/unistd.h>
@@ -80,6 +82,32 @@
 struct mtx	cdevpriv_mtx;
 MTX_SYSINIT(cdevpriv_mtx, &cdevpriv_mtx, "cdevpriv lock", MTX_DEF);
 
+SYSCTL_DECL(_vfs_devfs);
+
+static int devfs_dotimes;
+SYSCTL_INT(_vfs_devfs, OID_AUTO, dotimes, CTLFLAG_RW,
+    &devfs_dotimes, 0, "Update timestamps on DEVFS with default precision");
+
+/*
+ * Update devfs node timestamp.  Note that updates are unlocked and
+ * stat(2) could see partially updated times.
+ */
+static void
+devfs_timestamp(struct timespec *tsp)
+{
+	time_t ts;
+
+	if (devfs_dotimes) {
+		vfs_timestamp(tsp);
+	} else {
+		ts = time_second;
+		if (tsp->tv_sec != ts) {
+			tsp->tv_sec = ts;
+			tsp->tv_nsec = 0;
+		}
+	}
+}
+
 static int
 devfs_fp_check(struct file *fp, struct cdev **devp, struct cdevsw **dswp,
     int *ref)
@@ -119,7 +147,7 @@
 }
 
 int
-devfs_set_cdevpriv(void *priv, cdevpriv_dtr_t priv_dtr)
+devfs_set_cdevpriv(void *priv, d_priv_dtor_t *priv_dtr)
 {
 	struct file *fp;
 	struct cdev_priv *cdp;
@@ -212,11 +240,11 @@
 	if (DEVFS_DMP_DROP(dmp)) {
 		sx_xunlock(&dmp->dm_lock);
 		devfs_unmount_final(dmp);
-		return (EBADF);
+		return (ERESTART);
 	}
 	if ((vp->v_iflag & VI_DOOMED) != 0) {
 		sx_xunlock(&dmp->dm_lock);
-		return (EBADF);
+		return (ERESTART);
 	}
 	de = vp->v_data;
 	KASSERT(de != NULL,
@@ -223,7 +251,7 @@
 	    ("devfs_populate_vp: vp->v_data == NULL but vnode not doomed"));
 	if ((de->de_flags & DE_DOOMED) != 0) {
 		sx_xunlock(&dmp->dm_lock);
-		return (EBADF);
+		return (ERESTART);
 	}
 
 	return (0);
@@ -734,8 +762,10 @@
 
 	fpop = td->td_fpop;
 	error = devfs_fp_check(fp, &dev, &dsw, &ref);
-	if (error)
+	if (error != 0) {
+		error = vnops.fo_ioctl(fp, com, data, cred, td);
 		return (error);
+	}
 
 	if (com == FIODTYPE) {
 		*(int *)data = dsw->d_flags & D_TYPEMASK;
@@ -840,6 +870,7 @@
 	struct devfs_dirent *de, *dd;
 	struct devfs_dirent **dde;
 	struct devfs_mount *dmp;
+	struct mount *mp;
 	struct cdev *cdev;
 	int error, flags, nameiop, dvplocked;
 	char specname[SPECNAMELEN + 1], *pname;
@@ -851,7 +882,8 @@
 	td = cnp->cn_thread;
 	flags = cnp->cn_flags;
 	nameiop = cnp->cn_nameiop;
-	dmp = VFSTODEVFS(dvp->v_mount);
+	mp = dvp->v_mount;
+	dmp = VFSTODEVFS(mp);
 	dd = dvp->v_data;
 	*vpp = NULLVP;
 
@@ -884,8 +916,8 @@
 			return (ENOENT);
 		dvplocked = VOP_ISLOCKED(dvp);
 		VOP_UNLOCK(dvp, 0);
-		error = devfs_allocv(de, dvp->v_mount,
-		    cnp->cn_lkflags & LK_TYPE_MASK, vpp);
+		error = devfs_allocv(de, mp, cnp->cn_lkflags & LK_TYPE_MASK,
+		    vpp);
 		*dm_unlock = 0;
 		vn_lock(dvp, dvplocked | LK_RETRY);
 		return (error);
@@ -970,8 +1002,7 @@
 			return (0);
 		}
 	}
-	error = devfs_allocv(de, dvp->v_mount, cnp->cn_lkflags & LK_TYPE_MASK,
-	    vpp);
+	error = devfs_allocv(de, mp, cnp->cn_lkflags & LK_TYPE_MASK, vpp);
 	*dm_unlock = 0;
 	return (error);
 }
@@ -1021,6 +1052,9 @@
 	TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
 		if (cnp->cn_namelen != de->de_dirent->d_namlen)
 			continue;
+		if (de->de_dirent->d_type == DT_CHR &&
+		    (de->de_cdp->cdp_flags & CDP_ACTIVE) == 0)
+			continue;
 		if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
 		    de->de_dirent->d_namlen) != 0)
 			continue;
@@ -1082,7 +1116,7 @@
 		error = dsw->d_fdopen(dev, ap->a_mode, td, fp);
 	else
 		error = dsw->d_open(dev, ap->a_mode, S_IFCHR, td);
-	/* cleanup any cdevpriv upon error */
+	/* Clean up any cdevpriv upon error. */
 	if (error != 0)
 		devfs_clear_cdevpriv();
 	td->td_fpop = fpop;
@@ -1149,8 +1183,10 @@
 
 	fpop = td->td_fpop;
 	error = devfs_fp_check(fp, &dev, &dsw, &ref);
-	if (error)
-		return (poll_no_poll(events));
+	if (error != 0) {
+		error = vnops.fo_poll(fp, events, cred, td);
+		return (error);
+	}
 	error = dsw->d_poll(dev, events, td);
 	td->td_fpop = fpop;
 	dev_relthread(dev, ref);
@@ -1168,9 +1204,9 @@
 	return (0);
 }
 
-/* ARGSUSED */
 static int
-devfs_read_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td)
+devfs_read_f(struct file *fp, struct uio *uio, struct ucred *cred,
+    int flags, struct thread *td)
 {
 	struct cdev *dev;
 	int ioflag, error, ref;
@@ -1178,10 +1214,14 @@
 	struct cdevsw *dsw;
 	struct file *fpop;
 
+	if (uio->uio_resid > DEVFS_IOSIZE_MAX)
+		return (EINVAL);
 	fpop = td->td_fpop;
 	error = devfs_fp_check(fp, &dev, &dsw, &ref);
-	if (error)
+	if (error != 0) {
+		error = vnops.fo_read(fp, uio, cred, flags, td);
 		return (error);
+	}
 	resid = uio->uio_resid;
 	ioflag = fp->f_flag & (O_NONBLOCK | O_DIRECT);
 	if (ioflag & O_DIRECT)
@@ -1190,7 +1230,7 @@
 	foffset_lock_uio(fp, uio, flags | FOF_NOLOCK);
 	error = dsw->d_read(dev, uio, ioflag);
 	if (uio->uio_resid != resid || (error == 0 && resid != 0))
-		vfs_timestamp(&dev->si_atime);
+		devfs_timestamp(&dev->si_atime);
 	td->td_fpop = fpop;
 	dev_relthread(dev, ref);
 
@@ -1287,10 +1327,10 @@
 static int
 devfs_reclaim(struct vop_reclaim_args *ap)
 {
-	struct vnode *vp = ap->a_vp;
+	struct vnode *vp;
 	struct devfs_dirent *de;
-	struct cdev *dev;
 
+	vp = ap->a_vp;
 	mtx_lock(&devfs_de_interlock);
 	de = vp->v_data;
 	if (de != NULL) {
@@ -1298,24 +1338,31 @@
 		vp->v_data = NULL;
 	}
 	mtx_unlock(&devfs_de_interlock);
-
 	vnode_destroy_vobject(vp);
+	return (0);
+}
 
+static int
+devfs_reclaim_vchr(struct vop_reclaim_args *ap)
+{
+	struct vnode *vp;
+	struct cdev *dev;
+
+	vp = ap->a_vp;
+	MPASS(vp->v_type == VCHR);
+
+	devfs_reclaim(ap);
+
 	VI_LOCK(vp);
 	dev_lock();
 	dev = vp->v_rdev;
 	vp->v_rdev = NULL;
-
-	if (dev == NULL) {
-		dev_unlock();
-		VI_UNLOCK(vp);
-		return (0);
-	}
-
-	dev->si_usecount -= vp->v_usecount;
+	if (dev != NULL)
+		dev->si_usecount -= vp->v_usecount;
 	dev_unlock();
 	VI_UNLOCK(vp);
-	dev_rel(dev);
+	if (dev != NULL)
+		dev_rel(dev);
 	return (0);
 }
 
@@ -1371,7 +1418,7 @@
 	struct cdev *dev;
 	struct cdev_priv *cdp;
 	struct devfs_dirent *de;
-	int i;
+	u_int i;
 
 	KASSERT((ap->a_flags & REVOKEALL) != 0, ("devfs_revoke !REVOKEALL"));
 
@@ -1495,11 +1542,15 @@
 		return (EINVAL);
 	}
 
+	error = devfs_populate_vp(vp);
+	if (error != 0)
+		return (error);
+
 	de = vp->v_data;
 	if (vp->v_type == VDIR)
 		de = de->de_dir;
 
-	error = c = 0;
+	c = 0;
 	if (vap->va_uid == (uid_t)VNOVAL)
 		uid = de->de_uid;
 	else
@@ -1512,8 +1563,8 @@
 		if ((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid ||
 		    (gid != de->de_gid && !groupmember(gid, ap->a_cred))) {
 			error = priv_check(td, PRIV_VFS_CHOWN);
-			if (error)
-				return (error);
+			if (error != 0)
+				goto ret;
 		}
 		de->de_uid = uid;
 		de->de_gid = gid;
@@ -1523,8 +1574,8 @@
 	if (vap->va_mode != (mode_t)VNOVAL) {
 		if (ap->a_cred->cr_uid != de->de_uid) {
 			error = priv_check(td, PRIV_VFS_ADMIN);
-			if (error)
-				return (error);
+			if (error != 0)
+				goto ret;
 		}
 		de->de_mode = vap->va_mode;
 		c = 1;
@@ -1531,11 +1582,9 @@
 	}
 
 	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
-		/* See the comment in ufs_vnops::ufs_setattr(). */
-		if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td)) &&
-		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
-		    (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, td))))
-			return (error);
+		error = vn_utimes_perm(vp, vap, ap->a_cred, td);
+		if (error != 0)
+			goto ret;
 		if (vap->va_atime.tv_sec != VNOVAL) {
 			if (vp->v_type == VCHR)
 				vp->v_rdev->si_atime = vap->va_atime;
@@ -1557,7 +1606,10 @@
 		else
 			vfs_timestamp(&de->de_mtime);
 	}
-	return (0);
+
+ret:
+	sx_xunlock(&VFSTODEVFS(vp->v_mount)->dm_lock);
+	return (error);
 }
 
 #ifdef MAC
@@ -1643,9 +1695,9 @@
 	return (vnops.fo_truncate(fp, length, cred, td));
 }
 
-/* ARGSUSED */
 static int
-devfs_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td)
+devfs_write_f(struct file *fp, struct uio *uio, struct ucred *cred,
+    int flags, struct thread *td)
 {
 	struct cdev *dev;
 	int error, ioflag, ref;
@@ -1653,10 +1705,14 @@
 	struct cdevsw *dsw;
 	struct file *fpop;
 
+	if (uio->uio_resid > DEVFS_IOSIZE_MAX)
+		return (EINVAL);
 	fpop = td->td_fpop;
 	error = devfs_fp_check(fp, &dev, &dsw, &ref);
-	if (error)
+	if (error != 0) {
+		error = vnops.fo_write(fp, uio, cred, flags, td);
 		return (error);
+	}
 	KASSERT(uio->uio_td == td, ("uio_td %p is not td %p", uio->uio_td, td));
 	ioflag = fp->f_flag & (O_NONBLOCK | O_DIRECT | O_FSYNC);
 	if (ioflag & O_DIRECT)
@@ -1667,7 +1723,7 @@
 
 	error = dsw->d_write(dev, uio, ioflag);
 	if (uio->uio_resid != resid || (error == 0 && resid != 0)) {
-		vfs_timestamp(&dev->si_ctime);
+		devfs_timestamp(&dev->si_ctime);
 		dev->si_mtime = dev->si_ctime;
 	}
 	td->td_fpop = fpop;
@@ -1696,6 +1752,8 @@
 	.fo_close =	devfs_close_f,
 	.fo_chmod =	vn_chmod,
 	.fo_chown =	vn_chown,
+	.fo_sendfile =	vn_sendfile,
+	.fo_seek =	vn_seek,
 	.fo_flags =	DFLAG_PASSABLE | DFLAG_SEEKABLE
 };
 
@@ -1736,12 +1794,13 @@
 	.vop_mknod =		VOP_PANIC,
 	.vop_open =		devfs_open,
 	.vop_pathconf =		devfs_pathconf,
+	.vop_poll =		dead_poll,
 	.vop_print =		devfs_print,
-	.vop_read =		VOP_PANIC,
+	.vop_read =		dead_read,
 	.vop_readdir =		VOP_PANIC,
 	.vop_readlink =		VOP_PANIC,
 	.vop_reallocblks =	VOP_PANIC,
-	.vop_reclaim =		devfs_reclaim,
+	.vop_reclaim =		devfs_reclaim_vchr,
 	.vop_remove =		devfs_remove,
 	.vop_rename =		VOP_PANIC,
 	.vop_revoke =		devfs_revoke,
@@ -1753,7 +1812,7 @@
 	.vop_strategy =		VOP_PANIC,
 	.vop_symlink =		VOP_PANIC,
 	.vop_vptocnp =		devfs_vptocnp,
-	.vop_write =		VOP_PANIC,
+	.vop_write =		dead_write,
 };
 
 /*

Modified: trunk/sys/fs/ext2fs/ext2_alloc.c
===================================================================
--- trunk/sys/fs/ext2fs/ext2_alloc.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2_alloc.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  *  modified for Lites 1.1
  *
@@ -33,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)ffs_alloc.c	8.8 (Berkeley) 2/21/94
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_alloc.c 325750 2017-11-13 02:31:25Z pfg $
  */
 
 #include <sys/param.h>
@@ -46,10 +47,10 @@
 #include <sys/syslog.h>
 #include <sys/buf.h>
 
+#include <fs/ext2fs/fs.h>
 #include <fs/ext2fs/inode.h>
 #include <fs/ext2fs/ext2_mount.h>
 #include <fs/ext2fs/ext2fs.h>
-#include <fs/ext2fs/fs.h>
 #include <fs/ext2fs/ext2_extern.h>
 
 static daddr_t	ext2_alloccg(struct inode *, int, daddr_t, int);
@@ -63,7 +64,7 @@
 static daddr_t  ext2_mapsearch(struct m_ext2fs *, char *, daddr_t);
 
 /*
- * Allocate a block in the file system.
+ * Allocate a block in the filesystem.
  *
  * A preference may be optionally specified. If a preference is given
  * the following hierarchy is used to allocate a block:
@@ -80,18 +81,19 @@
  *        available block is located.
  */
 int
-ext2_alloc(struct inode *ip, int32_t lbn, int32_t bpref, int size,
-    struct ucred *cred, int32_t *bnp)
+ext2_alloc(struct inode *ip, daddr_t lbn, e4fs_daddr_t bpref, int size,
+    struct ucred *cred, e4fs_daddr_t *bnp)
 {
 	struct m_ext2fs *fs;
 	struct ext2mount *ump;
 	int32_t bno;
-	int cg;	
+	int cg;
+
 	*bnp = 0;
 	fs = ip->i_e2fs;
 	ump = ip->i_ump;
 	mtx_assert(EXT2_MTX(ump), MA_OWNED);
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 	if ((u_int)size > fs->e2fs_bsize || blkoff(fs, size) != 0) {
 		vn_printf(ip->i_devvp, "bsize = %lu, size = %d, fs = %s\n",
 		    (long unsigned int)fs->e2fs_bsize, size, fs->e2fs_fsmnt);
@@ -99,11 +101,11 @@
 	}
 	if (cred == NOCRED)
 		panic("ext2_alloc: missing credential");
-#endif /* DIAGNOSTIC */
+#endif		/* INVARIANTS */
 	if (size == fs->e2fs_bsize && fs->e2fs->e2fs_fbcount == 0)
 		goto nospace;
-	if (cred->cr_uid != 0 && 
-		fs->e2fs->e2fs_fbcount < fs->e2fs->e2fs_rbcount)
+	if (cred->cr_uid != 0 &&
+	    fs->e2fs->e2fs_fbcount < fs->e2fs->e2fs_rbcount)
 		goto nospace;
 	if (bpref >= fs->e2fs->e2fs_bcount)
 		bpref = 0;
@@ -112,7 +114,7 @@
 	else
 		cg = dtog(fs, bpref);
 	bno = (daddr_t)ext2_hashalloc(ip, cg, bpref, fs->e2fs_bsize,
-				      ext2_alloccg);
+	    ext2_alloccg);
 	if (bno > 0) {
 		/* set next_alloc fields as done in block_getblk */
 		ip->i_next_alloc_block = lbn;
@@ -122,11 +124,11 @@
 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
 		*bnp = bno;
 		return (0);
-        }
+	}
 nospace:
 	EXT2_UNLOCK(ump);
-	ext2_fserr(fs, cred->cr_uid, "file system full");
-	uprintf("\n%s: write failed, file system is full\n", fs->e2fs_fsmnt);
+	ext2_fserr(fs, cred->cr_uid, "filesystem full");
+	uprintf("\n%s: write failed, filesystem is full\n", fs->e2fs_fsmnt);
 	return (ENOSPC);
 }
 
@@ -147,11 +149,13 @@
 
 static SYSCTL_NODE(_vfs, OID_AUTO, ext2fs, CTLFLAG_RW, 0, "EXT2FS filesystem");
 
-static int doasyncfree = 0;
+static int doasyncfree = 1;
+
 SYSCTL_INT(_vfs_ext2fs, OID_AUTO, doasyncfree, CTLFLAG_RW, &doasyncfree, 0,
     "Use asychronous writes to update block pointers when freeing blocks");
 
 static int doreallocblks = 0;
+
 SYSCTL_INT(_vfs_ext2fs, OID_AUTO, doreallocblks, CTLFLAG_RW, &doreallocblks, 0, "");
 
 int
@@ -161,15 +165,17 @@
 	struct inode *ip;
 	struct vnode *vp;
 	struct buf *sbp, *ebp;
-	uint32_t *bap, *sbap, *ebap = 0;
+	uint32_t *bap, *sbap, *ebap;
 	struct ext2mount *ump;
 	struct cluster_save *buflist;
 	struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp;
-	int32_t start_lbn, end_lbn, soff, newblk, blkno;
+	e2fs_lbn_t start_lbn, end_lbn;
+	int soff;
+	e2fs_daddr_t newblk, blkno;
 	int i, len, start_lvl, end_lvl, pref, ssize;
 
 	if (doreallocblks == 0)
-		  return (ENOSPC);
+		return (ENOSPC);
 
 	vp = ap->a_vp;
 	ip = VTOI(vp);
@@ -183,7 +189,7 @@
 	len = buflist->bs_nchildren;
 	start_lbn = buflist->bs_children[0]->b_lblkno;
 	end_lbn = start_lbn + len - 1;
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 	for (i = 1; i < len; i++)
 		if (buflist->bs_children[i]->b_lblkno != start_lbn + i)
 			panic("ext2_reallocblks: non-cluster");
@@ -223,23 +229,24 @@
 			brelse(sbp);
 			return (ENOSPC);
 		}
-		sbap = (int32_t *)sbp->b_data;
+		sbap = (u_int *)sbp->b_data;
 		soff = idp->in_off;
 	}
 	/*
 	 * If the block range spans two block maps, get the second map.
 	 */
+	ebap = NULL;
 	if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) {
 		ssize = len;
 	} else {
-#ifdef DIAGNOSTIC
-		if (start_ap[start_lvl-1].in_lbn == idp->in_lbn)
+#ifdef INVARIANTS
+		if (start_ap[start_lvl - 1].in_lbn == idp->in_lbn)
 			panic("ext2_reallocblks: start == end");
 #endif
 		ssize = len - (idp->in_off + 1);
 		if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &ebp))
 			goto fail;
-		ebap = (int32_t *)ebp->b_data;
+		ebap = (u_int *)ebp->b_data;
 	}
 	/*
 	 * Find the preferred location for the cluster.
@@ -249,11 +256,11 @@
 	/*
 	 * Search the block map looking for an allocation of the desired size.
 	 */
-	if ((newblk = (int32_t)ext2_hashalloc(ip, dtog(fs, pref), pref,
-	    len, ext2_clusteralloc)) == 0){
+	if ((newblk = (e2fs_daddr_t)ext2_hashalloc(ip, dtog(fs, pref), pref,
+	    len, ext2_clusteralloc)) == 0) {
 		EXT2_UNLOCK(ump);
 		goto fail;
-	}	
+	}
 	/*
 	 * We have found a new contiguous block.
 	 *
@@ -264,7 +271,7 @@
 #ifdef DEBUG
 	printf("realloc: ino %d, lbns %jd-%jd\n\told:", ip->i_number,
 	    (intmax_t)start_lbn, (intmax_t)end_lbn);
-#endif /* DEBUG */
+#endif	/* DEBUG */
 	blkno = newblk;
 	for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->e2fs_fpb) {
 		if (i == ssize) {
@@ -271,13 +278,13 @@
 			bap = ebap;
 			soff = -i;
 		}
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 		if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap))
 			panic("ext2_reallocblks: alloc mismatch");
 #endif
 #ifdef DEBUG
-	printf(" %d,", *bap);
-#endif /* DEBUG */
+		printf(" %d,", *bap);
+#endif	/* DEBUG */
 		*bap++ = blkno;
 	}
 	/*
@@ -284,7 +291,7 @@
 	 * Next we must write out the modified inode and indirect blocks.
 	 * For strict correctness, the writes should be synchronous since
 	 * the old block values may have been written to disk. In practise
-	 * they are almost never written, but if we are concerned about 
+	 * they are almost never written, but if we are concerned about
 	 * strict correctness, the `doasyncfree' flag should be set to zero.
 	 *
 	 * The test on `doasyncfree' should be changed to test a flag
@@ -315,7 +322,7 @@
 	 */
 #ifdef DEBUG
 	printf("\n\tnew:");
-#endif /* DEBUG */
+#endif	/* DEBUG */
 	for (blkno = newblk, i = 0; i < len; i++, blkno += fs->e2fs_fpb) {
 		ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno),
 		    fs->e2fs_bsize);
@@ -322,11 +329,11 @@
 		buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno);
 #ifdef DEBUG
 		printf(" %d,", blkno);
-#endif /* DEBUG */
+#endif	/* DEBUG */
 	}
 #ifdef DEBUG
 	printf("\n");
-#endif /* DEBUG */
+#endif	/* DEBUG */
 	return (0);
 
 fail:
@@ -338,8 +345,8 @@
 }
 
 /*
- * Allocate an inode in the file system.
- * 
+ * Allocate an inode in the filesystem.
+ *
  */
 int
 ext2_valloc(struct vnode *pvp, int mode, struct ucred *cred, struct vnode **vpp)
@@ -351,7 +358,7 @@
 	struct ext2mount *ump;
 	ino_t ino, ipref;
 	int i, error, cg;
-	
+
 	*vpp = NULL;
 	pip = VTOI(pvp);
 	fs = pip->i_e2fs;
@@ -377,7 +384,7 @@
 	ipref = cg * fs->e2fs->e2fs_ipg + 1;
 	ino = (ino_t)ext2_hashalloc(pip, cg, (long)ipref, mode, ext2_nodealloccg);
 
-	if (ino == 0) 
+	if (ino == 0)
 		goto noinodes;
 	error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp);
 	if (error) {
@@ -391,22 +398,21 @@
 	 * Linux doesn't read the old inode in when it is allocating a
 	 * new one. I will set at least i_size and i_blocks to zero.
 	 */
+	ip->i_flag = 0;
 	ip->i_size = 0;
 	ip->i_blocks = 0;
 	ip->i_mode = 0;
 	ip->i_flags = 0;
-        /* now we want to make sure that the block pointers are zeroed out */
-        for (i = 0; i < NDADDR; i++)
-                ip->i_db[i] = 0;
-        for (i = 0; i < NIADDR; i++)
-                ip->i_ib[i] = 0;
+	/* now we want to make sure that the block pointers are zeroed out */
+	for (i = 0; i < NDADDR; i++)
+		ip->i_db[i] = 0;
+	for (i = 0; i < NIADDR; i++)
+		ip->i_ib[i] = 0;
 
 	/*
 	 * Set up a new generation number for this inode.
-	 * XXX check if this makes sense in ext2
 	 */
-	if (ip->i_gen == 0 || ++ip->i_gen == 0)
-		ip->i_gen = random() / 2 + 1;
+	ip->i_gen = arc4random();
 
 	vfs_timestamp(&ts);
 	ip->i_birthtime = ts.tv_sec;
@@ -441,18 +447,18 @@
 ext2_dirpref(struct inode *pip)
 {
 	struct m_ext2fs *fs;
-        int cg, prefcg, dirsize, cgsize;
-	int avgifree, avgbfree, avgndir, curdirsize;
-	int minifree, minbfree, maxndir;
-	int mincg, minndir;
-	int maxcontigdirs;
+	int cg, prefcg, cgsize;
+	u_int avgifree, avgbfree, avgndir, curdirsize;
+	u_int minifree, minbfree, maxndir;
+	u_int mincg, minndir;
+	u_int dirsize, maxcontigdirs;
 
 	mtx_assert(EXT2_MTX(pip->i_ump), MA_OWNED);
 	fs = pip->i_e2fs;
 
- 	avgifree = fs->e2fs->e2fs_ficount / fs->e2fs_gcount;
+	avgifree = fs->e2fs->e2fs_ficount / fs->e2fs_gcount;
 	avgbfree = fs->e2fs->e2fs_fbcount / fs->e2fs_gcount;
-	avgndir  = fs->e2fs_total_dir / fs->e2fs_gcount;
+	avgndir = fs->e2fs_total_dir / fs->e2fs_gcount;
 
 	/*
 	 * Force allocation in another cg if creating a first level dir.
@@ -471,15 +477,13 @@
 			}
 		for (cg = 0; cg < prefcg; cg++)
 			if (fs->e2fs_gd[cg].ext2bgd_ndirs < minndir &&
-                            fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree &&
-                            fs->e2fs_gd[cg].ext2bgd_nbfree >= avgbfree) {
-                                mincg = cg;
-                                minndir = fs->e2fs_gd[cg].ext2bgd_ndirs;
-                        }
-
+			    fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree &&
+			    fs->e2fs_gd[cg].ext2bgd_nbfree >= avgbfree) {
+				mincg = cg;
+				minndir = fs->e2fs_gd[cg].ext2bgd_ndirs;
+			}
 		return (mincg);
 	}
-
 	/*
 	 * Count various limits which used for
 	 * optimal allocation of a directory inode.
@@ -496,16 +500,13 @@
 	curdirsize = avgndir ? (cgsize - avgbfree * fs->e2fs_bsize) / avgndir : 0;
 	if (dirsize < curdirsize)
 		dirsize = curdirsize;
-	if (dirsize <= 0)
-		maxcontigdirs = 0;		/* dirsize overflowed */
-	else
-		maxcontigdirs = min((avgbfree * fs->e2fs_bsize) / dirsize, 255);
+	maxcontigdirs = min((avgbfree * fs->e2fs_bsize) / dirsize, 255);
 	maxcontigdirs = min(maxcontigdirs, fs->e2fs_ipg / AFPDIR);
 	if (maxcontigdirs == 0)
 		maxcontigdirs = 1;
 
 	/*
-	 * Limit number of dirs in one cg and reserve space for 
+	 * Limit number of dirs in one cg and reserve space for
 	 * regular files, but only if we have no deficit in
 	 * inodes or space.
 	 */
@@ -513,7 +514,7 @@
 	for (cg = prefcg; cg < fs->e2fs_gcount; cg++)
 		if (fs->e2fs_gd[cg].ext2bgd_ndirs < maxndir &&
 		    fs->e2fs_gd[cg].ext2bgd_nifree >= minifree &&
-	    	    fs->e2fs_gd[cg].ext2bgd_nbfree >= minbfree) {
+		    fs->e2fs_gd[cg].ext2bgd_nbfree >= minbfree) {
 			if (fs->e2fs_contigdirs[cg] < maxcontigdirs)
 				return (cg);
 		}
@@ -520,7 +521,7 @@
 	for (cg = 0; cg < prefcg; cg++)
 		if (fs->e2fs_gd[cg].ext2bgd_ndirs < maxndir &&
 		    fs->e2fs_gd[cg].ext2bgd_nifree >= minifree &&
-	    	    fs->e2fs_gd[cg].ext2bgd_nbfree >= minbfree) {
+		    fs->e2fs_gd[cg].ext2bgd_nbfree >= minbfree) {
 			if (fs->e2fs_contigdirs[cg] < maxcontigdirs)
 				return (cg);
 		}
@@ -537,7 +538,7 @@
 }
 
 /*
- * Select the desired position for the next block in a file.  
+ * Select the desired position for the next block in a file.
  *
  * we try to mimic what Remy does in inode_getblk/block_getblk
  *
@@ -549,34 +550,38 @@
  * of the above. Then, blocknr tells us the number of the block
  * that will hold the pointer
  */
-int32_t
-ext2_blkpref(struct inode *ip, int32_t lbn, int indx, int32_t *bap,
-    int32_t blocknr)
+e4fs_daddr_t
+ext2_blkpref(struct inode *ip, e2fs_lbn_t lbn, int indx, e2fs_daddr_t *bap,
+    e2fs_daddr_t blocknr)
 {
-	int	tmp;
+	int tmp;
+
 	mtx_assert(EXT2_MTX(ip->i_ump), MA_OWNED);
 
-	/* if the next block is actually what we thought it is,
-	   then set the goal to what we thought it should be
-	*/
+	/*
+	 * If the next block is actually what we thought it is, then set the
+	 * goal to what we thought it should be.
+	 */
 	if (ip->i_next_alloc_block == lbn && ip->i_next_alloc_goal != 0)
 		return ip->i_next_alloc_goal;
 
-	/* now check whether we were provided with an array that basically
-	   tells us previous blocks to which we want to stay closeby
-	*/
-	if (bap) 
-                for (tmp = indx - 1; tmp >= 0; tmp--) 
-			if (bap[tmp]) 
+	/*
+	 * Now check whether we were provided with an array that basically
+	 * tells us previous blocks to which we want to stay close.
+	 */
+	if (bap)
+		for (tmp = indx - 1; tmp >= 0; tmp--)
+			if (bap[tmp])
 				return bap[tmp];
 
-	/* else let's fall back to the blocknr, or, if there is none,
-	   follow the rule that a block should be allocated near its inode
-	*/
+	/*
+	 * Else lets fall back to the blocknr or, if there is none, follow
+	 * the rule that a block should be allocated near its inode.
+	 */
 	return blocknr ? blocknr :
-			(int32_t)(ip->i_block_group * 
-			EXT2_BLOCKS_PER_GROUP(ip->i_e2fs)) + 
-			ip->i_e2fs->e2fs->e2fs_first_dblock;
+	    (e2fs_daddr_t)(ip->i_block_group *
+	    EXT2_BLOCKS_PER_GROUP(ip->i_e2fs)) +
+	    ip->i_e2fs->e2fs->e2fs_first_dblock;
 }
 
 /*
@@ -589,7 +594,7 @@
  */
 static u_long
 ext2_hashalloc(struct inode *ip, int cg, long pref, int size,
-                daddr_t (*allocator)(struct inode *, int, daddr_t, int))
+    daddr_t (*allocator) (struct inode *, int, daddr_t, int))
 {
 	struct m_ext2fs *fs;
 	ino_t result;
@@ -653,8 +658,8 @@
 		return (0);
 	EXT2_UNLOCK(ump);
 	error = bread(ip->i_devvp, fsbtodb(fs,
-		fs->e2fs_gd[cg].ext2bgd_b_bitmap),
-		(int)fs->e2fs_bsize, NOCRED, &bp);
+	    fs->e2fs_gd[cg].ext2bgd_b_bitmap),
+	    (int)fs->e2fs_bsize, NOCRED, &bp);
 	if (error) {
 		brelse(bp);
 		EXT2_LOCK(ump);
@@ -740,18 +745,17 @@
 		start = 0;
 		goto retry;
 	}
-
 	bno = ext2_mapsearch(fs, bbp, bpref);
-	if (bno < 0){
+	if (bno < 0) {
 		brelse(bp);
 		EXT2_LOCK(ump);
 		return (0);
 	}
 gotit:
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 	if (isset(bbp, bno)) {
 		printf("ext2fs_alloccgblk: cg=%d bno=%jd fs=%s\n",
-			cg, (intmax_t)bno, fs->e2fs_fsmnt);
+		    cg, (intmax_t)bno, fs->e2fs_fsmnt);
 		panic("ext2fs_alloccg: dup alloc");
 	}
 #endif
@@ -794,8 +798,6 @@
 		goto fail_lock;
 
 	bbp = (char *)bp->b_data;
-	bp->b_xflags |= BX_BKGRDWRITE;
-
 	EXT2_LOCK(ump);
 	/*
 	 * Check to see if a cluster of the needed size (or bigger) is
@@ -813,9 +815,9 @@
 		 * to find no cluster.
 		 */
 		lp = &fs->e2fs_clustersum[cg].cs_sum[len - 1];
-			for (i = len - 1; i > 0; i--)
-				if (*lp-- > 0)
-					break;
+		for (i = len - 1; i > 0; i--)
+			if (*lp-- > 0)
+				break;
 		fs->e2fs_maxcluster[cg] = i;
 		goto fail;
 	}
@@ -888,9 +890,10 @@
 	struct m_ext2fs *fs;
 	struct buf *bp;
 	struct ext2mount *ump;
-	int error, start, len, loc, map, i;
-	char *ibp;
-	ipref--; /* to avoid a lot of (ipref -1) */
+	int error, start, len;
+	char *ibp, *loc;
+
+	ipref--;	/* to avoid a lot of (ipref -1) */
 	if (ipref == -1)
 		ipref = 0;
 	fs = ip->i_e2fs;
@@ -897,10 +900,10 @@
 	ump = ip->i_ump;
 	if (fs->e2fs_gd[cg].ext2bgd_nifree == 0)
 		return (0);
-	EXT2_UNLOCK(ump);	
+	EXT2_UNLOCK(ump);
 	error = bread(ip->i_devvp, fsbtodb(fs,
-		fs->e2fs_gd[cg].ext2bgd_i_bitmap),
-		(int)fs->e2fs_bsize, NOCRED, &bp);
+	    fs->e2fs_gd[cg].ext2bgd_i_bitmap),
+	    (int)fs->e2fs_bsize, NOCRED, &bp);
 	if (error) {
 		brelse(bp);
 		EXT2_LOCK(ump);
@@ -923,25 +926,19 @@
 	}
 	start = ipref / NBBY;
 	len = howmany(fs->e2fs->e2fs_ipg - ipref, NBBY);
-	loc = skpc(0xff, len, &ibp[start]);
-	if (loc == 0) {
+	loc = memcchr(&ibp[start], 0xff, len);
+	if (loc == NULL) {
 		len = start + 1;
 		start = 0;
-		loc = skpc(0xff, len, &ibp[0]);
-		if (loc == 0) {
+		loc = memcchr(&ibp[start], 0xff, len);
+		if (loc == NULL) {
 			printf("cg = %d, ipref = %lld, fs = %s\n",
-				cg, (long long)ipref, fs->e2fs_fsmnt);
+			    cg, (long long)ipref, fs->e2fs_fsmnt);
 			panic("ext2fs_nodealloccg: map corrupted");
 			/* NOTREACHED */
 		}
-	} 
-	i = start + len - loc;
-	map = ibp[i] ^ 0xff;
-	if (map == 0) {
-		printf("fs = %s\n", fs->e2fs_fsmnt);
-		panic("ext2fs_nodealloccg: block not in map");
 	}
-	ipref = i * NBBY + ffs(map) - 1;
+	ipref = (loc - ibp) * NBBY + ffs(~*loc) - 1;
 gotit:
 	setbit(ibp, ipref);
 	EXT2_LOCK(ump);
@@ -954,7 +951,7 @@
 	}
 	EXT2_UNLOCK(ump);
 	bdwrite(bp);
-	return (cg * fs->e2fs->e2fs_ipg + ipref +1);
+	return (cg * fs->e2fs->e2fs_ipg + ipref + 1);
 }
 
 /*
@@ -962,7 +959,7 @@
  *
  */
 void
-ext2_blkfree(struct inode *ip, int32_t bno, long size)
+ext2_blkfree(struct inode *ip, e4fs_daddr_t bno, long size)
 {
 	struct m_ext2fs *fs;
 	struct buf *bp;
@@ -974,33 +971,33 @@
 	ump = ip->i_ump;
 	cg = dtog(fs, bno);
 	if ((u_int)bno >= fs->e2fs->e2fs_bcount) {
-                printf("bad block %lld, ino %llu\n", (long long)bno,
-                    (unsigned long long)ip->i_number);
-                ext2_fserr(fs, ip->i_uid, "bad block");
-                return;
-        }
-        error = bread(ip->i_devvp,
-                fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
-                (int)fs->e2fs_bsize, NOCRED, &bp);
-        if (error) {
-                brelse(bp);
-                return;
-        }
-        bbp = (char *)bp->b_data;
-        bno = dtogd(fs, bno);
-        if (isclr(bbp, bno)) {
-                printf("block = %lld, fs = %s\n",
-                     (long long)bno, fs->e2fs_fsmnt);
-                panic("ext2_blkfree: freeing free block");
-        }
-        clrbit(bbp, bno);
+		printf("bad block %lld, ino %llu\n", (long long)bno,
+		    (unsigned long long)ip->i_number);
+		ext2_fserr(fs, ip->i_uid, "bad block");
+		return;
+	}
+	error = bread(ip->i_devvp,
+	    fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
+	    (int)fs->e2fs_bsize, NOCRED, &bp);
+	if (error) {
+		brelse(bp);
+		return;
+	}
+	bbp = (char *)bp->b_data;
+	bno = dtogd(fs, bno);
+	if (isclr(bbp, bno)) {
+		printf("block = %lld, fs = %s\n",
+		    (long long)bno, fs->e2fs_fsmnt);
+		panic("ext2_blkfree: freeing free block");
+	}
+	clrbit(bbp, bno);
 	EXT2_LOCK(ump);
 	ext2_clusteracct(fs, bbp, cg, bno, 1);
-        fs->e2fs->e2fs_fbcount++;
-        fs->e2fs_gd[cg].ext2bgd_nbfree++;
-        fs->e2fs_fmod = 1;
+	fs->e2fs->e2fs_fbcount++;
+	fs->e2fs_gd[cg].ext2bgd_nbfree++;
+	fs->e2fs_fmod = 1;
 	EXT2_UNLOCK(ump);
-        bdwrite(bp);
+	bdwrite(bp);
 }
 
 /*
@@ -1015,19 +1012,19 @@
 	struct buf *bp;
 	struct ext2mount *ump;
 	int error, cg;
-	char * ibp;
+	char *ibp;
 
 	pip = VTOI(pvp);
 	fs = pip->i_e2fs;
 	ump = pip->i_ump;
 	if ((u_int)ino > fs->e2fs_ipg * fs->e2fs_gcount)
-		panic("ext2_vfree: range: devvp = %p, ino = %d, fs = %s",
-		    pip->i_devvp, ino, fs->e2fs_fsmnt);
+		panic("ext2_vfree: range: devvp = %p, ino = %ju, fs = %s",
+		    pip->i_devvp, (uintmax_t)ino, fs->e2fs_fsmnt);
 
 	cg = ino_to_cg(fs, ino);
 	error = bread(pip->i_devvp,
-		fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
-		(int)fs->e2fs_bsize, NOCRED, &bp);
+	    fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
+	    (int)fs->e2fs_bsize, NOCRED, &bp);
 	if (error) {
 		brelse(bp);
 		return (0);
@@ -1036,7 +1033,7 @@
 	ino = (ino - 1) % fs->e2fs->e2fs_ipg;
 	if (isclr(ibp, ino)) {
 		printf("ino = %llu, fs = %s\n",
-			 (unsigned long long)ino, fs->e2fs_fsmnt);
+		    (unsigned long long)ino, fs->e2fs_fsmnt);
 		if (fs->e2fs_ronly == 0)
 			panic("ext2_vfree: freeing free inode");
 	}
@@ -1063,7 +1060,8 @@
 static daddr_t
 ext2_mapsearch(struct m_ext2fs *fs, char *bbp, daddr_t bpref)
 {
-	int start, len, loc, i, map;
+	char *loc;
+	int start, len;
 
 	/*
 	 * find the fragment by searching through the free block
@@ -1074,30 +1072,24 @@
 	else
 		start = 0;
 	len = howmany(fs->e2fs->e2fs_fpg, NBBY) - start;
-	loc = skpc(0xff, len, &bbp[start]);
-	if (loc == 0) {
+	loc = memcchr(&bbp[start], 0xff, len);
+	if (loc == NULL) {
 		len = start + 1;
 		start = 0;
-		loc = skpc(0xff, len, &bbp[start]);
-		if (loc == 0) {
+		loc = memcchr(&bbp[start], 0xff, len);
+		if (loc == NULL) {
 			printf("start = %d, len = %d, fs = %s\n",
-				start, len, fs->e2fs_fsmnt);
+			    start, len, fs->e2fs_fsmnt);
 			panic("ext2_mapsearch: map corrupted");
 			/* NOTREACHED */
 		}
 	}
-	i = start + len - loc;
-	map = bbp[i] ^ 0xff;
-	if (map == 0) {
-		printf("fs = %s\n", fs->e2fs_fsmnt);
-		panic("ext2fs_mapsearch: block not in map");
-	}
-	return (i * NBBY + ffs(map) - 1);
+	return ((loc - bbp) * NBBY + ffs(~*loc) - 1);
 }
 
 /*
- * Fserr prints the name of a file system with an error diagnostic.
- * 
+ * Fserr prints the name of a filesystem with an error diagnostic.
+ *
  * The form of the error message is:
  *	fs: error message
  */
@@ -1111,14 +1103,14 @@
 int
 cg_has_sb(int i)
 {
-        int a3, a5, a7;
+	int a3, a5, a7;
 
-        if (i == 0 || i == 1)
-                return 1;
-        for (a3 = 3, a5 = 5, a7 = 7;
-            a3 <= i || a5 <= i || a7 <= i;
-            a3 *= 3, a5 *= 5, a7 *= 7)
-                if (i == a3 || i == a5 || i == a7)
-                        return 1;
-        return 0;
+	if (i == 0 || i == 1)
+		return 1;
+	for (a3 = 3, a5 = 5, a7 = 7;
+	    a3 <= i || a5 <= i || a7 <= i;
+	    a3 *= 3, a5 *= 5, a7 *= 7)
+		if (i == a3 || i == a5 || i == a7)
+			return 1;
+	return 0;
 }

Modified: trunk/sys/fs/ext2fs/ext2_balloc.c
===================================================================
--- trunk/sys/fs/ext2fs/ext2_balloc.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2_balloc.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  *  modified for Lites 1.1
  *
@@ -33,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)ffs_balloc.c	8.4 (Berkeley) 9/23/93
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_balloc.c 311232 2017-01-04 02:43:33Z pfg $
  */
 
 #include <sys/param.h>
@@ -44,27 +45,29 @@
 #include <sys/mount.h>
 #include <sys/vnode.h>
 
+#include <fs/ext2fs/fs.h>
 #include <fs/ext2fs/inode.h>
 #include <fs/ext2fs/ext2fs.h>
-#include <fs/ext2fs/fs.h>
+#include <fs/ext2fs/ext2_dinode.h>
 #include <fs/ext2fs/ext2_extern.h>
 #include <fs/ext2fs/ext2_mount.h>
+
 /*
- * Balloc defines the structure of file system storage
+ * Balloc defines the structure of filesystem storage
  * by allocating the physical blocks on a device given
  * the inode and the logical block number in a file.
  */
 int
-ext2_balloc(struct inode *ip, int32_t lbn, int size, struct ucred *cred,
+ext2_balloc(struct inode *ip, e2fs_lbn_t lbn, int size, struct ucred *cred,
     struct buf **bpp, int flags)
 {
 	struct m_ext2fs *fs;
 	struct ext2mount *ump;
-	int32_t nb;
 	struct buf *bp, *nbp;
 	struct vnode *vp = ITOV(ip);
 	struct indir indirs[NIADDR + 2];
-	uint32_t newb, *bap, pref;
+	e4fs_daddr_t nb, newb;
+	e2fs_daddr_t *bap, pref;
 	int osize, nsize, num, i, error;
 
 	*bpp = NULL;
@@ -74,22 +77,23 @@
 	ump = ip->i_ump;
 
 	/*
-	 * check if this is a sequential block allocation. 
-	 * If so, increment next_alloc fields to allow ext2_blkpref 
+	 * check if this is a sequential block allocation.
+	 * If so, increment next_alloc fields to allow ext2_blkpref
 	 * to make a good guess
 	 */
-        if (lbn == ip->i_next_alloc_block + 1) {
+	if (lbn == ip->i_next_alloc_block + 1) {
 		ip->i_next_alloc_block++;
 		ip->i_next_alloc_goal++;
 	}
-
 	/*
 	 * The first NDADDR blocks are direct blocks
 	 */
 	if (lbn < NDADDR) {
 		nb = ip->i_db[lbn];
-		/* no new block is to be allocated, and no need to expand
-		   the file */
+		/*
+		 * no new block is to be allocated, and no need to expand
+		 * the file
+		 */
 		if (nb != 0 && ip->i_size >= (lbn + 1) * fs->e2fs_bsize) {
 			error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp);
 			if (error) {
@@ -114,10 +118,13 @@
 				}
 				bp->b_blkno = fsbtodb(fs, nb);
 			} else {
-			/* Godmar thinks: this shouldn't happen w/o fragments */
-				printf("nsize %d(%d) > osize %d(%d) nb %d\n", 
-					(int)nsize, (int)size, (int)osize, 
-					(int)ip->i_size, (int)nb);
+				/*
+				 * Godmar thinks: this shouldn't happen w/o
+				 * fragments
+				 */
+				printf("nsize %d(%d) > osize %d(%d) nb %d\n",
+				    (int)nsize, (int)size, (int)osize,
+				    (int)ip->i_size, (int)nb);
 				panic(
 				    "ext2_balloc: Something is terribly wrong");
 /*
@@ -152,9 +159,9 @@
 	pref = 0;
 	if ((error = ext2_getlbns(vp, lbn, indirs, &num)) != 0)
 		return (error);
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 	if (num < 1)
-		panic ("ext2_balloc: ext2_getlbns returned indirect block");
+		panic("ext2_balloc: ext2_getlbns returned indirect block");
 #endif
 	/*
 	 * Fetch the first indirect block allocating if necessary.
@@ -163,10 +170,10 @@
 	nb = ip->i_ib[indirs[0].in_off];
 	if (nb == 0) {
 		EXT2_LOCK(ump);
-		pref = ext2_blkpref(ip, lbn, indirs[0].in_off + 
-					     EXT2_NDIR_BLOCKS, &ip->i_db[0], 0);
-	        if ((error = ext2_alloc(ip, lbn, pref, 
-			(int)fs->e2fs_bsize, cred, &newb)))
+		pref = ext2_blkpref(ip, lbn, indirs[0].in_off +
+		    EXT2_NDIR_BLOCKS, &ip->i_db[0], 0);
+		if ((error = ext2_alloc(ip, lbn, pref, fs->e2fs_bsize, cred,
+		    &newb)))
 			return (error);
 		nb = newb;
 		bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0, 0);
@@ -193,7 +200,7 @@
 			brelse(bp);
 			return (error);
 		}
-		bap = (int32_t *)bp->b_data;
+		bap = (e2fs_daddr_t *)bp->b_data;
 		nb = bap[indirs[i].in_off];
 		if (i == num)
 			break;
@@ -205,8 +212,8 @@
 		EXT2_LOCK(ump);
 		if (pref == 0)
 			pref = ext2_blkpref(ip, lbn, indirs[i].in_off, bap,
-						bp->b_lblkno);
-		error =  ext2_alloc(ip, lbn, pref, (int)fs->e2fs_bsize, cred, &newb);
+			    bp->b_lblkno);
+		error = ext2_alloc(ip, lbn, pref, (int)fs->e2fs_bsize, cred, &newb);
 		if (error) {
 			brelse(bp);
 			return (error);
@@ -243,8 +250,8 @@
 	 */
 	if (nb == 0) {
 		EXT2_LOCK(ump);
-		pref = ext2_blkpref(ip, lbn, indirs[i].in_off, &bap[0], 
-				bp->b_lblkno);
+		pref = ext2_blkpref(ip, lbn, indirs[i].in_off, &bap[0],
+		    bp->b_lblkno);
 		if ((error = ext2_alloc(ip,
 		    lbn, pref, (int)fs->e2fs_bsize, cred, &newb)) != 0) {
 			brelse(bp);
@@ -263,7 +270,7 @@
 		if (flags & IO_SYNC) {
 			bwrite(bp);
 		} else {
-		if (bp->b_bufsize == fs->e2fs_bsize)
+			if (bp->b_bufsize == fs->e2fs_bsize)
 				bp->b_flags |= B_CLUSTEROK;
 			bdwrite(bp);
 		}
@@ -273,10 +280,11 @@
 	brelse(bp);
 	if (flags & BA_CLRBUF) {
 		int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT;
+
 		if (seqcount && (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
 			error = cluster_read(vp, ip->i_size, lbn,
 			    (int)fs->e2fs_bsize, NOCRED,
-			    MAXBSIZE, seqcount, &nbp);
+			    MAXBSIZE, seqcount, 0, &nbp);
 		} else {
 			error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp);
 		}
@@ -291,4 +299,3 @@
 	*bpp = nbp;
 	return (0);
 }
-

Modified: trunk/sys/fs/ext2fs/ext2_bmap.c
===================================================================
--- trunk/sys/fs/ext2fs/ext2_bmap.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2_bmap.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1989, 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -32,7 +33,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)ufs_bmap.c	8.7 (Berkeley) 3/21/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_bmap.c 311232 2017-01-04 02:43:33Z pfg $
  */
 
 #include <sys/param.h>
@@ -46,10 +47,14 @@
 #include <sys/stat.h>
 
 #include <fs/ext2fs/inode.h>
+#include <fs/ext2fs/fs.h>
 #include <fs/ext2fs/ext2fs.h>
+#include <fs/ext2fs/ext2_dinode.h>
 #include <fs/ext2fs/ext2_extern.h>
 #include <fs/ext2fs/ext2_mount.h>
 
+static int ext4_bmapext(struct vnode *, int32_t, int64_t *, int *, int *);
+
 /*
  * Bmap converts the logical block number of a file to its physical block
  * number on the disk. The conversion is done by using the logical block
@@ -58,7 +63,7 @@
 int
 ext2_bmap(struct vop_bmap_args *ap)
 {
-	int32_t blkno;
+	daddr_t blkno;
 	int error;
 
 	/*
@@ -70,13 +75,64 @@
 	if (ap->a_bnp == NULL)
 		return (0);
 
-	error = ext2_bmaparray(ap->a_vp, ap->a_bn, &blkno,
-	    ap->a_runp, ap->a_runb);
+	if (VTOI(ap->a_vp)->i_flag & IN_E4EXTENTS)
+		error = ext4_bmapext(ap->a_vp, ap->a_bn, &blkno,
+		    ap->a_runp, ap->a_runb);
+	else
+		error = ext2_bmaparray(ap->a_vp, ap->a_bn, &blkno,
+		    ap->a_runp, ap->a_runb);
 	*ap->a_bnp = blkno;
 	return (error);
 }
 
 /*
+ * This function converts the logical block number of a file to
+ * its physical block number on the disk within ext4 extents.
+ */
+static int
+ext4_bmapext(struct vnode *vp, int32_t bn, int64_t *bnp, int *runp, int *runb)
+{
+	struct inode *ip;
+	struct m_ext2fs *fs;
+	struct ext4_extent *ep;
+	struct ext4_extent_path path = {.ep_bp = NULL};
+	daddr_t lbn;
+	int ret = 0;
+
+	ip = VTOI(vp);
+	fs = ip->i_e2fs;
+	lbn = bn;
+
+	/*
+	 * TODO: need to implement read ahead to improve the performance.
+	 */
+	if (runp != NULL)
+		*runp = 0;
+
+	if (runb != NULL)
+		*runb = 0;
+
+	ext4_ext_find_extent(fs, ip, lbn, &path);
+	ep = path.ep_ext;
+	if (ep == NULL)
+		ret = EIO;
+	else {
+		*bnp = fsbtodb(fs, lbn - ep->e_blk +
+		    (ep->e_start_lo | (daddr_t)ep->e_start_hi << 32));
+
+		if (*bnp == 0)
+			*bnp = -1;
+	}
+
+	if (path.ep_bp != NULL) {
+		brelse(path.ep_bp);
+		path.ep_bp = NULL;
+	}
+
+	return (ret);
+}
+
+/*
  * Indirect blocks are now on the vnode for the file.  They are given negative
  * logical block numbers.  Indirect blocks are addressed by the negative
  * address of the first data block to which they point.  Double indirect blocks
@@ -91,16 +147,15 @@
  */
 
 int
-ext2_bmaparray(struct vnode *vp, int32_t bn, int32_t *bnp, int *runp, int *runb)
+ext2_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, int *runp, int *runb)
 {
 	struct inode *ip;
 	struct buf *bp;
 	struct ext2mount *ump;
 	struct mount *mp;
-	struct vnode *devvp;
-	struct indir a[NIADDR+1], *ap;
-	int32_t daddr;
-	long metalbn;
+	struct indir a[NIADDR + 1], *ap;
+	daddr_t daddr;
+	e2fs_lbn_t metalbn;
 	int error, num, maxrun = 0, bsize;
 	int *nump;
 
@@ -108,7 +163,6 @@
 	ip = VTOI(vp);
 	mp = vp->v_mount;
 	ump = VFSTOEXT2(mp);
-	devvp = ump->um_devvp;
 
 	bsize = EXT2_BLOCK_SIZE(ump->um_e2fs);
 
@@ -116,10 +170,8 @@
 		maxrun = mp->mnt_iosize_max / bsize - 1;
 		*runp = 0;
 	}
-
-	if (runb) {
+	if (runb)
 		*runb = 0;
-	}
 
 
 	ap = a;
@@ -134,7 +186,8 @@
 		if (*bnp == 0) {
 			*bnp = -1;
 		} else if (runp) {
-			int32_t bnb = bn;
+			daddr_t bnb = bn;
+
 			for (++bn; bn < NDADDR && *runp < maxrun &&
 			    is_sequential(ump, ip->i_db[bn - 1], ip->i_db[bn]);
 			    ++bn, ++*runp);
@@ -142,7 +195,7 @@
 			if (runb && (bn > 0)) {
 				for (--bn; (bn >= 0) && (*runb < maxrun) &&
 					is_sequential(ump, ip->i_db[bn],
-						ip->i_db[bn+1]);
+						ip->i_db[bn + 1]);
 						--bn, ++*runb);
 			}
 		}
@@ -149,7 +202,6 @@
 		return (0);
 	}
 
-
 	/* Get disk address out of indirect block array */
 	daddr = ip->i_ib[ap->in_off];
 
@@ -172,7 +224,7 @@
 
 		bp = getblk(vp, metalbn, bsize, 0, 0, 0);
 		if ((bp->b_flags & B_CACHE) == 0) {
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 			if (!daddr)
 				panic("ext2_bmaparray: indirect block not in cache");
 #endif
@@ -191,20 +243,21 @@
 			}
 		}
 
-		daddr = ((int32_t *)bp->b_data)[ap->in_off];
+		daddr = ((e2fs_daddr_t *)bp->b_data)[ap->in_off];
 		if (num == 1 && daddr && runp) {
 			for (bn = ap->in_off + 1;
 			    bn < MNINDIR(ump) && *runp < maxrun &&
 			    is_sequential(ump,
-			    ((int32_t *)bp->b_data)[bn - 1],
-			    ((int32_t *)bp->b_data)[bn]);
+			    ((e2fs_daddr_t *)bp->b_data)[bn - 1],
+			    ((e2fs_daddr_t *)bp->b_data)[bn]);
 			    ++bn, ++*runp);
 			bn = ap->in_off;
 			if (runb && bn) {
 				for (--bn; bn >= 0 && *runb < maxrun &&
-			    		is_sequential(ump, ((int32_t *)bp->b_data)[bn],
-					    ((int32_t *)bp->b_data)[bn+1]);
-			    		--bn, ++*runb);
+					is_sequential(ump,
+					((e2fs_daddr_t *)bp->b_data)[bn],
+					((e2fs_daddr_t *)bp->b_data)[bn + 1]);
+					--bn, ++*runb);
 			}
 		}
 	}
@@ -218,7 +271,7 @@
 	 * return a request for a zeroed out buffer if attempts are made
 	 * to read a BLK_NOCOPY or BLK_SNAP block.
 	 */
-	if ((ip->i_flags & SF_SNAPSHOT) && daddr > 0 && daddr < ump->um_seqinc){
+	if ((ip->i_flags & SF_SNAPSHOT) && daddr > 0 && daddr < ump->um_seqinc) {
 		*bnp = -1;
 		return (0);
 	}
@@ -239,9 +292,10 @@
  * once with the offset into the page itself.
  */
 int
-ext2_getlbns(struct vnode *vp, int32_t bn, struct indir *ap, int *nump)
+ext2_getlbns(struct vnode *vp, daddr_t bn, struct indir *ap, int *nump)
 {
-	long blockcnt, metalbn, realbn;
+	long blockcnt;
+	e2fs_lbn_t metalbn, realbn;
 	struct ext2mount *ump;
 	int i, numlevels, off;
 	int64_t qblockcnt;

Modified: trunk/sys/fs/ext2fs/ext2_dinode.h
===================================================================
--- trunk/sys/fs/ext2fs/ext2_dinode.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2_dinode.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2009 Aditya Sarawgi
  * All rights reserved.
@@ -23,11 +24,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_dinode.h 305494 2016-09-06 19:53:05Z pfg $
  */
 
 #ifndef _FS_EXT2FS_EXT2_DINODE_H_
-#define _FS_EXT2FS_EXT2_DINODE_H_
+#define	_FS_EXT2FS_EXT2_DINODE_H_
 
 /*
  * Special inode numbers
@@ -44,43 +45,62 @@
 #define	EXT2_UNDELDIRINO	((ino_t)6)
 #define	EXT2_RESIZEINO		((ino_t)7)
 #define	EXT2_JOURNALINO		((ino_t)8)
+#define	EXT2_EXCLUDEINO		((ino_t)9)
+#define	EXT2_REPLICAINO		((ino_t)10)
 #define	EXT2_FIRSTINO		((ino_t)11)
 
 /*
  * Inode flags
- * The current implementation uses only EXT2_IMMUTABLE and EXT2_APPEND flags
+ * The system supports EXT2_IMMUTABLE, EXT2_APPEND and EXT2_NODUMP flags.
+ * The current implementation also uses EXT3_INDEX, EXT4_EXTENTS and
+ * EXT4_HUGE_FILE with some restrictions, imposed the lack of write
+ * support.
  */
-#define EXT2_SECRM		0x00000001	/* Secure deletion */
-#define EXT2_UNRM		0x00000002	/* Undelete */
-#define EXT2_COMPR		0x00000004	/* Compress file */
-#define EXT2_SYNC		0x00000008	/* Synchronous updates */
-#define EXT2_IMMUTABLE		0x00000010	/* Immutable file */
-#define EXT2_APPEND		0x00000020 /* writes to file may only append */
-#define EXT2_NODUMP		0x00000040	/* do not dump file */
-#define EXT2_NOATIME		0x00000080	/* do not update atime */
+#define	EXT2_SECRM		0x00000001	/* Secure deletion */
+#define	EXT2_UNRM		0x00000002	/* Undelete */
+#define	EXT2_COMPR		0x00000004	/* Compress file */
+#define	EXT2_SYNC		0x00000008	/* Synchronous updates */
+#define	EXT2_IMMUTABLE		0x00000010	/* Immutable file */
+#define	EXT2_APPEND		0x00000020 /* Writes to file may only append */
+#define	EXT2_NODUMP		0x00000040	/* Do not dump file */
+#define	EXT2_NOATIME		0x00000080	/* Do not update atime */
+#define	EXT3_INDEX		0x00001000	/* Hash-indexed directory */
+#define	EXT4_IMAGIC		0x00002000	/* AFS directory */
+#define	EXT4_JOURNAL_DATA	0x00004000 /* File data should be journaled */
+#define	EXT4_NOTAIL		0x00008000 /* File tail should not be merged */
+#define	EXT4_DIRSYNC		0x00010000	/* Dirsync behaviour */
+#define	EXT4_TOPDIR		0x00020000 /* Top of directory hierarchies*/
+#define	EXT4_HUGE_FILE		0x00040000	/* Set to each huge file */
+#define	EXT4_EXTENTS		0x00080000	/* Inode uses extents */
+#define	EXT4_EA_INODE		0x00200000	/* Inode used for large EA */
+#define	EXT4_EOFBLOCKS		0x00400000 /* Blocks allocated beyond EOF */
+#define	EXT4_INLINE_DATA	0x10000000 /* Inode has inline data */
+#define	EXT4_PROJINHERIT	0x20000000 /* Children inherit project ID */
 
-#define EXT4_INDEX		0x00001000 	/* hash-indexed directory */
-#define EXT4_IMAGIC		0x00002000 	/* AFS directory */
-#define EXT4_JOURNAL_DATA	0x00004000 /* file data should be journaled */
-#define EXT4_NOTAIL		0x00008000 /* file tail should not be merged */
-#define EXT4_DIRSYNC		0x00010000	/* dirsync behaviour */
-#define EXT4_TOPDIR		0x00020000 /* Top of directory hierarchies*/
-#define EXT4_HUGE_FILE		0x00040000	/* Set to each huge file */
-#define EXT4_EXTENTS		0x00080000	/* Inode uses extents */
-#define EXT4_EOFBLOCKS		0x00400000 /* Blocks allocated beyond EOF */
-
 /*
  * Definitions for nanosecond timestamps.
  * Ext3 inode versioning, 2006-12-13.
  */
-#define EXT3_EPOCH_BITS	2
-#define EXT3_EPOCH_MASK	((1 << EXT3_EPOCH_BITS) - 1)
-#define EXT3_NSEC_MASK	(~0UL << EXT3_EPOCH_BITS)
+#define	EXT3_EPOCH_BITS	2
+#define	EXT3_EPOCH_MASK	((1 << EXT3_EPOCH_BITS) - 1)
+#define	EXT3_NSEC_MASK	(~0UL << EXT3_EPOCH_BITS)
 
-#define E2DI_HAS_XTIME(ip)	(EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs,	\
+#define	E2DI_HAS_XTIME(ip)	(EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs,	\
 				    EXT2F_ROCOMPAT_EXTRA_ISIZE))
+#define	E2DI_HAS_HUGE_FILE(ip)	(EXT2_HAS_RO_COMPAT_FEATURE(ip->i_e2fs,	\
+				    EXT2F_ROCOMPAT_HUGE_FILE))
 
 /*
+ * Constants relative to the data blocks
+ */
+#define	EXT2_NDIR_BLOCKS		12
+#define	EXT2_IND_BLOCK			EXT2_NDIR_BLOCKS
+#define	EXT2_DIND_BLOCK			(EXT2_IND_BLOCK + 1)
+#define	EXT2_TIND_BLOCK			(EXT2_DIND_BLOCK + 1)
+#define	EXT2_N_BLOCKS			(EXT2_TIND_BLOCK + 1)
+#define	EXT2_MAXSYMLINKLEN		(EXT2_N_BLOCKS * sizeof(uint32_t))
+
+/*
  * Structure of an inode on the disk
  */
 struct ext2fs_dinode {
@@ -105,16 +125,17 @@
 	uint16_t	e2di_facl_high;	/* 118: File EA bits 47:32 */
 	uint16_t	e2di_uid_high;	/* 120: Owner UID top 16 bits */
 	uint16_t	e2di_gid_high;	/* 122: Owner GID top 16 bits */
-	uint16_t	e2di_chksum_lo;   /* 124: Lower inode checksum */
+	uint16_t	e2di_chksum_lo;	  /* 124: Lower inode checksum */
 	uint16_t	e2di_lx_reserved; /* 126: Unused */
 	uint16_t	e2di_extra_isize; /* 128: Size of this inode */
 	uint16_t	e2di_chksum_hi;	/* 130: High inode checksum */
-	uint32_t        e2di_ctime_extra; /* 132: Extra change time */
-	uint32_t        e2di_mtime_extra; /* 136: Extra modification time */
-	uint32_t        e2di_atime_extra; /* 140: Extra access time */
-	uint32_t        e2di_crtime;	/* 144: Creation (birth)time */
-	uint32_t        e2di_crtime_extra; /* 148: Extra creation (birth)time */
-	uint32_t        e2di_version_hi;  /* 152: High bits of inode version */
+	uint32_t	e2di_ctime_extra; /* 132: Extra change time */
+	uint32_t	e2di_mtime_extra; /* 136: Extra modification time */
+	uint32_t	e2di_atime_extra; /* 140: Extra access time */
+	uint32_t	e2di_crtime;	/* 144: Creation (birth)time */
+	uint32_t	e2di_crtime_extra; /* 148: Extra creation (birth)time */
+	uint32_t	e2di_version_hi;  /* 152: High bits of inode version */
+	uint32_t	e2di_projid;	/* 156: Project ID */
 };
 
 #endif /* !_FS_EXT2FS_EXT2_DINODE_H_ */

Modified: trunk/sys/fs/ext2fs/ext2_dir.h
===================================================================
--- trunk/sys/fs/ext2fs/ext2_dir.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2_dir.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2009 Aditya Sarawgi
  * All rights reserved.
@@ -23,23 +24,38 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_dir.h 311232 2017-01-04 02:43:33Z pfg $
  */
 
 #ifndef _FS_EXT2FS_EXT2_DIR_H_
-#define _FS_EXT2FS_EXT2_DIR_H_
+#define	_FS_EXT2FS_EXT2_DIR_H_
 
 /*
  * Structure of a directory entry
  */
-#define EXT2FS_MAXNAMLEN 255
+#define	EXT2FS_MAXNAMLEN	255
 
-struct	ext2fs_direct {
+struct ext2fs_direct {
 	uint32_t e2d_ino;		/* inode number of entry */
 	uint16_t e2d_reclen;		/* length of this record */
 	uint16_t e2d_namlen;		/* length of string in e2d_name */
 	char e2d_name[EXT2FS_MAXNAMLEN];/* name with length<=EXT2FS_MAXNAMLEN */
 };
+
+enum slotstatus {
+	NONE,
+	COMPACT,
+	FOUND
+};
+
+struct ext2fs_searchslot {
+	enum slotstatus slotstatus;
+	doff_t	slotoffset;		/* offset of area with free space */
+	int	slotsize;		/* size of area at slotoffset */
+	int	slotfreespace;		/* amount of space free in slot */
+	int	slotneeded;		/* sizeof the entry we are seeking */
+};
+
 /*
  * The new version of the directory entry.  Since EXT2 structures are
  * stored in intel byte order, and the name_len field could never be
@@ -46,36 +62,41 @@
  * bigger than 255 chars, it's safe to reclaim the extra byte for the
  * file_type field.
  */
-struct	ext2fs_direct_2 {
+struct ext2fs_direct_2 {
 	uint32_t e2d_ino;		/* inode number of entry */
 	uint16_t e2d_reclen;		/* length of this record */
-	uint8_t e2d_namlen;		/* length of string in e2d_name */
-	uint8_t e2d_type;		/* file type */
-	char e2d_name[EXT2FS_MAXNAMLEN];/* name with length<=EXT2FS_MAXNAMLEN */
+	uint8_t	e2d_namlen;		/* length of string in e2d_name */
+	uint8_t	e2d_type;		/* file type */
+	char	e2d_name[EXT2FS_MAXNAMLEN];	/* name with
+						 * length<=EXT2FS_MAXNAMLEN */
 };
+
 /*
+ * Maximal count of links to a file
+ */
+#define	EXT2_LINK_MAX	32000
+
+/*
  * Ext2 directory file types.  Only the low 3 bits are used.  The
  * other bits are reserved for now.
  */
-#define EXT2_FT_UNKNOWN		0
-#define EXT2_FT_REG_FILE	1
-#define EXT2_FT_DIR		2
-#define EXT2_FT_CHRDEV		3
-#define EXT2_FT_BLKDEV 		4
-#define EXT2_FT_FIFO		5
-#define EXT2_FT_SOCK		6
-#define EXT2_FT_SYMLINK		7
+#define	EXT2_FT_UNKNOWN		0
+#define	EXT2_FT_REG_FILE	1
+#define	EXT2_FT_DIR		2
+#define	EXT2_FT_CHRDEV		3
+#define	EXT2_FT_BLKDEV 		4
+#define	EXT2_FT_FIFO		5
+#define	EXT2_FT_SOCK		6
+#define	EXT2_FT_SYMLINK		7
+#define	EXT2_FT_MAX		8
 
-#define EXT2_FT_MAX		8
-
 /*
  * EXT2_DIR_PAD defines the directory entries boundaries
  *
  * NOTE: It must be a multiple of 4
  */
-#define EXT2_DIR_PAD		 	4
-#define EXT2_DIR_ROUND 			(EXT2_DIR_PAD - 1)
-#define EXT2_DIR_REC_LEN(name_len)	(((name_len) + 8 + EXT2_DIR_ROUND) & \
+#define	EXT2_DIR_PAD		 	4
+#define	EXT2_DIR_ROUND			(EXT2_DIR_PAD - 1)
+#define	EXT2_DIR_REC_LEN(name_len)	(((name_len) + 8 + EXT2_DIR_ROUND) & \
 					 ~EXT2_DIR_ROUND)
-#endif /* !_FS_EXT2FS_EXT2_DIR_H_ */
-
+#endif	/* !_FS_EXT2FS_EXT2_DIR_H_ */

Added: trunk/sys/fs/ext2fs/ext2_extents.c
===================================================================
--- trunk/sys/fs/ext2fs/ext2_extents.c	                        (rev 0)
+++ trunk/sys/fs/ext2fs/ext2_extents.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -0,0 +1,176 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2010 Zheng Liu <lz at freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_extents.c 311232 2017-01-04 02:43:33Z pfg $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
+
+#include <fs/ext2fs/ext2_mount.h>
+#include <fs/ext2fs/fs.h>
+#include <fs/ext2fs/inode.h>
+#include <fs/ext2fs/ext2fs.h>
+#include <fs/ext2fs/ext2_extents.h>
+#include <fs/ext2fs/ext2_extern.h>
+
+static void ext4_ext_binsearch_index(struct inode *ip, struct ext4_extent_path
+		*path, daddr_t lbn)
+{
+	struct ext4_extent_header *ehp = path->ep_header;
+	struct ext4_extent_index *l, *r, *m;
+
+	l = (struct ext4_extent_index *)(char *)(ehp + 1);
+	r = (struct ext4_extent_index *)(char *)(ehp + 1) + ehp->eh_ecount - 1;
+	while (l <= r) {
+		m = l + (r - l) / 2;
+		if (lbn < m->ei_blk)
+			r = m - 1;
+		else
+			l = m + 1;
+	}
+
+	path->ep_index = l - 1;
+}
+
+static void
+ext4_ext_binsearch(struct inode *ip, struct ext4_extent_path *path, daddr_t lbn)
+{
+	struct ext4_extent_header *ehp = path->ep_header;
+	struct ext4_extent *l, *r, *m;
+
+	if (ehp->eh_ecount == 0)
+		return;
+
+	l = (struct ext4_extent *)(char *)(ehp + 1);
+	r = (struct ext4_extent *)(char *)(ehp + 1) + ehp->eh_ecount - 1;
+	while (l <= r) {
+		m = l + (r - l) / 2;
+		if (lbn < m->e_blk)
+			r = m - 1;
+		else
+			l = m + 1;
+	}
+
+	path->ep_ext = l - 1;
+}
+
+/*
+ * Find a block in ext4 extent cache.
+ */
+int
+ext4_ext_in_cache(struct inode *ip, daddr_t lbn, struct ext4_extent *ep)
+{
+	struct ext4_extent_cache *ecp;
+	int ret = EXT4_EXT_CACHE_NO;
+
+	ecp = &ip->i_ext_cache;
+
+	/* cache is invalid */
+	if (ecp->ec_type == EXT4_EXT_CACHE_NO)
+		return (ret);
+
+	if (lbn >= ecp->ec_blk && lbn < ecp->ec_blk + ecp->ec_len) {
+		ep->e_blk = ecp->ec_blk;
+		ep->e_start_lo = ecp->ec_start & 0xffffffff;
+		ep->e_start_hi = ecp->ec_start >> 32 & 0xffff;
+		ep->e_len = ecp->ec_len;
+		ret = ecp->ec_type;
+	}
+	return (ret);
+}
+
+/*
+ * Put an ext4_extent structure in ext4 cache.
+ */
+void
+ext4_ext_put_cache(struct inode *ip, struct ext4_extent *ep, int type)
+{
+	struct ext4_extent_cache *ecp;
+
+	ecp = &ip->i_ext_cache;
+	ecp->ec_type = type;
+	ecp->ec_blk = ep->e_blk;
+	ecp->ec_len = ep->e_len;
+	ecp->ec_start = (daddr_t)ep->e_start_hi << 32 | ep->e_start_lo;
+}
+
+/*
+ * Find an extent.
+ */
+struct ext4_extent_path *
+ext4_ext_find_extent(struct m_ext2fs *fs, struct inode *ip,
+    daddr_t lbn, struct ext4_extent_path *path)
+{
+	struct ext4_extent_header *ehp;
+	uint16_t i;
+	int error, size;
+	daddr_t nblk;
+
+	ehp = (struct ext4_extent_header *)(char *)ip->i_db;
+
+	if (ehp->eh_magic != EXT4_EXT_MAGIC)
+		return (NULL);
+
+	path->ep_header = ehp;
+
+	for (i = ehp->eh_depth; i != 0; --i) {
+		ext4_ext_binsearch_index(ip, path, lbn);
+		path->ep_depth = 0;
+		path->ep_ext = NULL;
+
+		nblk = (daddr_t)path->ep_index->ei_leaf_hi << 32 |
+		    path->ep_index->ei_leaf_lo;
+		size = blksize(fs, ip, nblk);
+		if (path->ep_bp != NULL) {
+			brelse(path->ep_bp);
+			path->ep_bp = NULL;
+		}
+		error = bread(ip->i_devvp, fsbtodb(fs, nblk), size, NOCRED,
+		    &path->ep_bp);
+		if (error) {
+			brelse(path->ep_bp);
+			path->ep_bp = NULL;
+			return (NULL);
+		}
+		ehp = (struct ext4_extent_header *)path->ep_bp->b_data;
+		path->ep_header = ehp;
+	}
+
+	path->ep_depth = i;
+	path->ep_ext = NULL;
+	path->ep_index = NULL;
+
+	ext4_ext_binsearch(ip, path, lbn);
+	return (path);
+}


Property changes on: trunk/sys/fs/ext2fs/ext2_extents.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/fs/ext2fs/ext2_extents.h
===================================================================
--- trunk/sys/fs/ext2fs/ext2_extents.h	                        (rev 0)
+++ trunk/sys/fs/ext2fs/ext2_extents.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -0,0 +1,101 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2012, 2010 Zheng Liu <lz at freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_extents.h 311232 2017-01-04 02:43:33Z pfg $
+ */
+#ifndef _FS_EXT2FS_EXT2_EXTENTS_H_
+#define	_FS_EXT2FS_EXT2_EXTENTS_H_
+
+#include <sys/types.h>
+
+#define	EXT4_EXT_MAGIC  0xf30a
+
+#define	EXT4_EXT_CACHE_NO	0
+#define	EXT4_EXT_CACHE_GAP	1
+#define	EXT4_EXT_CACHE_IN	2
+
+/*
+ * Ext4 file system extent on disk.
+ */
+struct ext4_extent {
+	uint32_t e_blk;	/* first logical block */
+	uint16_t e_len;	/* number of blocks */
+	uint16_t e_start_hi;	/* high 16 bits of physical block */
+	uint32_t e_start_lo;	/* low 32 bits of physical block */
+};
+
+/*
+ * Extent index on disk.
+ */
+struct ext4_extent_index {
+	uint32_t ei_blk;	/* indexes logical blocks */
+	uint32_t ei_leaf_lo;	/* points to physical block of the
+				 * next level */
+	uint16_t ei_leaf_hi;	/* high 16 bits of physical block */
+	uint16_t ei_unused;
+};
+
+/*
+ * Extent tree header.
+ */
+struct ext4_extent_header {
+	uint16_t eh_magic;		/* magic number: 0xf30a */
+	uint16_t eh_ecount;		/* number of valid entries */
+	uint16_t eh_max;		/* capacity of store in entries */
+	uint16_t eh_depth;		/* the depth of extent tree */
+	uint32_t eh_gen;		/* generation of extent tree */
+};
+
+/*
+ * Save cached extent.
+ */
+struct ext4_extent_cache {
+	daddr_t	ec_start;		/* extent start */
+	uint32_t ec_blk;		/* logical block */
+	uint32_t ec_len;
+	uint32_t ec_type;
+};
+
+/*
+ * Save path to some extent.
+ */
+struct ext4_extent_path {
+	uint16_t ep_depth;
+	struct buf *ep_bp;
+	struct ext4_extent *ep_ext;
+	struct ext4_extent_index *ep_index;
+	struct ext4_extent_header *ep_header;
+};
+
+struct inode;
+struct m_ext2fs;
+int	ext4_ext_in_cache(struct inode *, daddr_t, struct ext4_extent *);
+void	ext4_ext_put_cache(struct inode *, struct ext4_extent *, int);
+struct ext4_extent_path *
+ext4_ext_find_extent(struct m_ext2fs *fs,
+    struct inode *, daddr_t, struct ext4_extent_path *);
+
+#endif	/* !_FS_EXT2FS_EXT2_EXTENTS_H_ */


Property changes on: trunk/sys/fs/ext2fs/ext2_extents.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/fs/ext2fs/ext2_extern.h
===================================================================
--- trunk/sys/fs/ext2fs/ext2_extern.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2_extern.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  *  modified for EXT2FS support in Lites 1.1
  *
@@ -33,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)ffs_extern.h	8.3 (Berkeley) 4/16/94
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_extern.h 311232 2017-01-04 02:43:33Z pfg $
  */
 
 #ifndef _FS_EXT2FS_EXT2_EXTERN_H_
@@ -40,6 +41,8 @@
 #define	_FS_EXT2FS_EXT2_EXTERN_H_
 
 struct ext2fs_dinode;
+struct ext2fs_direct_2;
+struct ext2fs_searchslot;
 struct indir;
 struct inode;
 struct mount;
@@ -46,32 +49,35 @@
 struct vfsconf;
 struct vnode;
 
-int	ext2_alloc(struct inode *,
-	    int32_t, int32_t, int, struct ucred *, int32_t *);
+int	ext2_add_entry(struct vnode *, struct ext2fs_direct_2 *);
+int	ext2_alloc(struct inode *, daddr_t, e4fs_daddr_t, int,
+	    struct ucred *, e4fs_daddr_t *);
 int	ext2_balloc(struct inode *,
-	    int32_t, int, struct ucred *, struct buf **, int);
+	    e2fs_lbn_t, int, struct ucred *, struct buf **, int);
 int	ext2_blkatoff(struct vnode *, off_t, char **, struct buf **);
-void	ext2_blkfree(struct inode *, int32_t, long);
-int32_t	ext2_blkpref(struct inode *, int32_t, int, int32_t *, int32_t);
+void	ext2_blkfree(struct inode *,  e4fs_daddr_t, long);
+e4fs_daddr_t	ext2_blkpref(struct inode *, e2fs_lbn_t, int, e2fs_daddr_t *,
+	    e2fs_daddr_t);
 int	ext2_bmap(struct vop_bmap_args *);
-int	ext2_bmaparray(struct vnode *, int32_t, int32_t *, int *, int *);
+int	ext2_bmaparray(struct vnode *, daddr_t, daddr_t *, int *, int *);
 void	ext2_clusteracct(struct m_ext2fs *, char *, int, daddr_t, int);
 void	ext2_dirbad(struct inode *ip, doff_t offset, char *how);
 void	ext2_ei2i(struct ext2fs_dinode *, struct inode *);
-int	ext2_getlbns(struct vnode *, int32_t, struct indir *, int *);
+int	ext2_getlbns(struct vnode *, daddr_t, struct indir *, int *);
 void	ext2_i2ei(struct inode *, struct ext2fs_dinode *);
-int     ext2_reallocblks(struct vop_reallocblks_args *);
 void	ext2_itimes(struct vnode *vp);
+int	ext2_reallocblks(struct vop_reallocblks_args *);
 int	ext2_reclaim(struct vop_reclaim_args *);
-void	ext2_setblock(struct m_ext2fs *, u_char *, int32_t);
 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 *, struct vop_vector *, struct vnode **vpp);
-int 	ext2_lookup(struct vop_cachedlookup_args *);
-int 	ext2_readdir(struct vop_readdir_args *);
+int	ext2_lookup(struct vop_cachedlookup_args *);
+int	ext2_readdir(struct vop_readdir_args *);
+#ifdef EXT2FS_DEBUG
 void	ext2_print_inode(struct inode *);
+#endif
 int	ext2_direnter(struct inode *, 
 		struct vnode *, struct componentname *);
 int	ext2_dirremove(struct vnode *, struct componentname *);
@@ -81,7 +87,19 @@
 int	ext2_checkpath(struct inode *, struct inode *, struct ucred *);
 int	cg_has_sb(int i);
 int	ext2_inactive(struct vop_inactive_args *);
+int	ext2_htree_add_entry(struct vnode *, struct ext2fs_direct_2 *,
+	    struct componentname *);
+int	ext2_htree_create_index(struct vnode *, struct componentname *,
+	    struct ext2fs_direct_2 *);
+int	ext2_htree_has_idx(struct inode *);
+int	ext2_htree_hash(const char *, int, uint32_t *, int, uint32_t *,
+	    uint32_t *);
+int	ext2_htree_lookup(struct inode *, const char *, int, struct buf **,
+	    int *, doff_t *, doff_t *, doff_t *, struct ext2fs_searchslot *);
+int	ext2_search_dirblock(struct inode *, void *, int *, const char *, int,
+	    int *, doff_t *, doff_t *, doff_t *, struct ext2fs_searchslot *);
 
+
 /* Flags to low-level allocation routines.
  * The low 16-bits are reserved for IO_ flags from vnode.h.
  */
@@ -93,4 +111,4 @@
 extern struct vop_vector ext2_vnodeops;
 extern struct vop_vector ext2_fifoops;
 
-#endif /* !_FS_EXT2FS_EXT2_EXTERN_H_ */
+#endif	/* !_FS_EXT2FS_EXT2_EXTERN_H_ */

Added: trunk/sys/fs/ext2fs/ext2_hash.c
===================================================================
--- trunk/sys/fs/ext2fs/ext2_hash.c	                        (rev 0)
+++ trunk/sys/fs/ext2fs/ext2_hash.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -0,0 +1,317 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2010, 2013 Zheng Liu <lz at freebsd.org>
+ * Copyright (c) 2012, Vyacheslav Matyushin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_hash.c 311232 2017-01-04 02:43:33Z pfg $
+ */
+
+/*
+ * The following notice applies to the code in ext2_half_md4():
+ *
+ * Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD4 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD4 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/vnode.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#include <fs/ext2fs/htree.h>
+#include <fs/ext2fs/inode.h>
+#include <fs/ext2fs/ext2_mount.h>
+#include <fs/ext2fs/ext2_extern.h>
+
+/* F, G, and H are MD4 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+/*
+ * FF, GG, and HH are transformations for rounds 1, 2, and 3.
+ * Rotation is separated from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s) { \
+	(a) += F ((b), (c), (d)) + (x); \
+	(a) = ROTATE_LEFT ((a), (s)); \
+}
+
+#define GG(a, b, c, d, x, s) { \
+	(a) += G ((b), (c), (d)) + (x) + (uint32_t)0x5A827999; \
+	(a) = ROTATE_LEFT ((a), (s)); \
+}
+
+#define HH(a, b, c, d, x, s) { \
+	(a) += H ((b), (c), (d)) + (x) + (uint32_t)0x6ED9EBA1; \
+	(a) = ROTATE_LEFT ((a), (s)); \
+}
+
+/*
+ * MD4 basic transformation.  It transforms state based on block.
+ *
+ * This is a half md4 algorithm since Linux uses this algorithm for dir
+ * index.  This function is derived from the RSA Data Security, Inc. MD4
+ * Message-Digest Algorithm and was modified as necessary.
+ *
+ * The return value of this function is uint32_t in Linux, but actually we don't
+ * need to check this value, so in our version this function doesn't return any
+ * value.
+ */
+static void
+ext2_half_md4(uint32_t hash[4], uint32_t data[8])
+{
+	uint32_t a = hash[0], b = hash[1], c = hash[2], d = hash[3];
+
+	/* Round 1 */
+	FF(a, b, c, d, data[0],  3);
+	FF(d, a, b, c, data[1],  7);
+	FF(c, d, a, b, data[2], 11);
+	FF(b, c, d, a, data[3], 19);
+	FF(a, b, c, d, data[4],  3);
+	FF(d, a, b, c, data[5],  7);
+	FF(c, d, a, b, data[6], 11);
+	FF(b, c, d, a, data[7], 19);
+
+	/* Round 2 */
+	GG(a, b, c, d, data[1],  3);
+	GG(d, a, b, c, data[3],  5);
+	GG(c, d, a, b, data[5],  9);
+	GG(b, c, d, a, data[7], 13);
+	GG(a, b, c, d, data[0],  3);
+	GG(d, a, b, c, data[2],  5);
+	GG(c, d, a, b, data[4],  9);
+	GG(b, c, d, a, data[6], 13);
+
+	/* Round 3 */
+	HH(a, b, c, d, data[3],  3);
+	HH(d, a, b, c, data[7],  9);
+	HH(c, d, a, b, data[2], 11);
+	HH(b, c, d, a, data[6], 15);
+	HH(a, b, c, d, data[1],  3);
+	HH(d, a, b, c, data[5],  9);
+	HH(c, d, a, b, data[0], 11);
+	HH(b, c, d, a, data[4], 15);
+
+	hash[0] += a;
+	hash[1] += b;
+	hash[2] += c;
+	hash[3] += d;
+}
+
+/*
+ * Tiny Encryption Algorithm.
+ */
+static void
+ext2_tea(uint32_t hash[4], uint32_t data[8])
+{
+	uint32_t tea_delta = 0x9E3779B9;
+	uint32_t sum;
+	uint32_t x = hash[0], y = hash[1];
+	int n = 16;
+	int i = 1;
+
+	while (n-- > 0) {
+		sum = i * tea_delta;
+		x += ((y << 4) + data[0]) ^ (y + sum) ^ ((y >> 5) + data[1]);
+		y += ((x << 4) + data[2]) ^ (x + sum) ^ ((x >> 5) + data[3]);
+		i++;
+	}
+
+	hash[0] += x;
+	hash[1] += y;
+}
+
+static uint32_t
+ext2_legacy_hash(const char *name, int len, int unsigned_char)
+{
+	uint32_t h0, h1 = 0x12A3FE2D, h2 = 0x37ABE8F9;
+	uint32_t multi = 0x6D22F5;
+	const unsigned char *uname = (const unsigned char *)name;
+	const signed char *sname = (const signed char *)name;
+	int val, i;
+
+	for (i = 0; i < len; i++) {
+		if (unsigned_char)
+			val = (u_int)*uname++;
+		else
+			val = (int)*sname++;
+
+		h0 = h2 + (h1 ^ (val * multi));
+		if (h0 & 0x80000000)
+			h0 -= 0x7FFFFFFF;
+		h2 = h1;
+		h1 = h0;
+	}
+
+	return (h1 << 1);
+}
+
+static void
+ext2_prep_hashbuf(const char *src, int slen, uint32_t *dst, int dlen,
+    int unsigned_char)
+{
+	uint32_t padding = slen | (slen << 8) | (slen << 16) | (slen << 24);
+	uint32_t buf_val;
+	const unsigned char *ubuf = (const unsigned char *)src;
+	const signed char *sbuf = (const signed char *)src;
+	int len, i;
+	int buf_byte;
+
+	if (slen > dlen)
+		len = dlen;
+	else
+		len = slen;
+
+	buf_val = padding;
+
+	for (i = 0; i < len; i++) {
+		if (unsigned_char)
+			buf_byte = (u_int)ubuf[i];
+		else
+			buf_byte = (int)sbuf[i];
+
+		if ((i % 4) == 0)
+			buf_val = padding;
+
+		buf_val <<= 8;
+		buf_val += buf_byte;
+
+		if ((i % 4) == 3) {
+			*dst++ = buf_val;
+			dlen -= sizeof(uint32_t);
+			buf_val = padding;
+		}
+	}
+
+	dlen -= sizeof(uint32_t);
+	if (dlen >= 0)
+		*dst++ = buf_val;
+
+	dlen -= sizeof(uint32_t);
+	while (dlen >= 0) {
+		*dst++ = padding;
+		dlen -= sizeof(uint32_t);
+	}
+}
+
+int
+ext2_htree_hash(const char *name, int len,
+    uint32_t *hash_seed, int hash_version,
+    uint32_t *hash_major, uint32_t *hash_minor)
+{
+	uint32_t hash[4];
+	uint32_t data[8];
+	uint32_t major = 0, minor = 0;
+	int unsigned_char = 0;
+
+	if (!name || !hash_major)
+		return (-1);
+
+	if (len < 1 || len > 255)
+		goto error;
+
+	hash[0] = 0x67452301;
+	hash[1] = 0xEFCDAB89;
+	hash[2] = 0x98BADCFE;
+	hash[3] = 0x10325476;
+
+	if (hash_seed)
+		memcpy(hash, hash_seed, sizeof(hash));
+
+	switch (hash_version) {
+	case EXT2_HTREE_TEA_UNSIGNED:
+		unsigned_char = 1;
+		/* FALLTHROUGH */
+	case EXT2_HTREE_TEA:
+		while (len > 0) {
+			ext2_prep_hashbuf(name, len, data, 16, unsigned_char);
+			ext2_tea(hash, data);
+			len -= 16;
+			name += 16;
+		}
+		major = hash[0];
+		minor = hash[1];
+		break;
+	case EXT2_HTREE_LEGACY_UNSIGNED:
+		unsigned_char = 1;
+		/* FALLTHROUGH */
+	case EXT2_HTREE_LEGACY:
+		major = ext2_legacy_hash(name, len, unsigned_char);
+		break;
+	case EXT2_HTREE_HALF_MD4_UNSIGNED:
+		unsigned_char = 1;
+		/* FALLTHROUGH */
+	case EXT2_HTREE_HALF_MD4:
+		while (len > 0) {
+			ext2_prep_hashbuf(name, len, data, 32, unsigned_char);
+			ext2_half_md4(hash, data);
+			len -= 32;
+			name += 32;
+		}
+		major = hash[1];
+		minor = hash[2];
+		break;
+	default:
+		goto error;
+	}
+
+	major &= ~1;
+	if (major == (EXT2_HTREE_EOF << 1))
+		major = (EXT2_HTREE_EOF - 1) << 1;
+	*hash_major = major;
+	if (hash_minor)
+		*hash_minor = minor;
+
+	return (0);
+
+error:
+	*hash_major = 0;
+	if (hash_minor)
+		*hash_minor = 0;
+	return (-1);
+}


Property changes on: trunk/sys/fs/ext2fs/ext2_hash.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/sys/fs/ext2fs/ext2_htree.c
===================================================================
--- trunk/sys/fs/ext2fs/ext2_htree.c	                        (rev 0)
+++ trunk/sys/fs/ext2fs/ext2_htree.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -0,0 +1,902 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2010, 2012 Zheng Liu <lz at freebsd.org>
+ * Copyright (c) 2012, Vyacheslav Matyushin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_htree.c 314227 2017-02-24 21:38:41Z pfg $
+ */
+
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/endian.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+#include <sys/sysctl.h>
+
+#include <ufs/ufs/dir.h>
+
+#include <fs/ext2fs/inode.h>
+#include <fs/ext2fs/ext2_mount.h>
+#include <fs/ext2fs/ext2fs.h>
+#include <fs/ext2fs/fs.h>
+#include <fs/ext2fs/ext2_extern.h>
+#include <fs/ext2fs/ext2_dinode.h>
+#include <fs/ext2fs/ext2_dir.h>
+#include <fs/ext2fs/htree.h>
+
+static void	ext2_append_entry(char *block, uint32_t blksize,
+		    struct ext2fs_direct_2 *last_entry,
+		    struct ext2fs_direct_2 *new_entry);
+static int	ext2_htree_append_block(struct vnode *vp, char *data,
+		    struct componentname *cnp, uint32_t blksize);
+static int	ext2_htree_check_next(struct inode *ip, uint32_t hash,
+		    const char *name, struct ext2fs_htree_lookup_info *info);
+static int	ext2_htree_cmp_sort_entry(const void *e1, const void *e2);
+static int	ext2_htree_find_leaf(struct inode *ip, const char *name,
+		    int namelen, uint32_t *hash, uint8_t *hash_version,
+		    struct ext2fs_htree_lookup_info *info);
+static uint32_t ext2_htree_get_block(struct ext2fs_htree_entry *ep);
+static uint16_t	ext2_htree_get_count(struct ext2fs_htree_entry *ep);
+static uint32_t ext2_htree_get_hash(struct ext2fs_htree_entry *ep);
+static uint16_t	ext2_htree_get_limit(struct ext2fs_htree_entry *ep);
+static void	ext2_htree_insert_entry_to_level(struct ext2fs_htree_lookup_level *level,
+		    uint32_t hash, uint32_t blk);
+static void	ext2_htree_insert_entry(struct ext2fs_htree_lookup_info *info,
+		    uint32_t hash, uint32_t blk);
+static uint32_t	ext2_htree_node_limit(struct inode *ip);
+static void	ext2_htree_set_block(struct ext2fs_htree_entry *ep,
+		    uint32_t blk);
+static void	ext2_htree_set_count(struct ext2fs_htree_entry *ep,
+		    uint16_t cnt);
+static void	ext2_htree_set_hash(struct ext2fs_htree_entry *ep,
+		    uint32_t hash);
+static void	ext2_htree_set_limit(struct ext2fs_htree_entry *ep,
+		    uint16_t limit);
+static int	ext2_htree_split_dirblock(char *block1, char *block2,
+		    uint32_t blksize, uint32_t *hash_seed, uint8_t hash_version,
+		    uint32_t *split_hash, struct  ext2fs_direct_2 *entry);
+static void	ext2_htree_release(struct ext2fs_htree_lookup_info *info);
+static uint32_t	ext2_htree_root_limit(struct inode *ip, int len);
+static int	ext2_htree_writebuf(struct ext2fs_htree_lookup_info *info);
+
+int
+ext2_htree_has_idx(struct inode *ip)
+{
+	if (EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_DIRHASHINDEX) &&
+	    ip->i_flag & IN_E3INDEX)
+		return (1);
+	else
+		return (0);
+}
+
+static int
+ext2_htree_check_next(struct inode *ip, uint32_t hash, const char *name,
+    struct ext2fs_htree_lookup_info *info)
+{
+	struct vnode *vp = ITOV(ip);
+	struct ext2fs_htree_lookup_level *level;
+	struct buf *bp;
+	uint32_t next_hash;
+	int idx = info->h_levels_num - 1;
+	int levels = 0;
+
+	do {
+		level = &info->h_levels[idx];
+		level->h_entry++;
+		if (level->h_entry < level->h_entries +
+		    ext2_htree_get_count(level->h_entries))
+			break;
+		if (idx == 0)
+			return (0);
+		idx--;
+		levels++;
+	} while (1);
+
+	next_hash = ext2_htree_get_hash(level->h_entry);
+	if ((hash & 1) == 0) {
+		if (hash != (next_hash & ~1))
+			return (0);
+	}
+
+	while (levels > 0) {
+		levels--;
+		if (ext2_blkatoff(vp, ext2_htree_get_block(level->h_entry) *
+		    ip->i_e2fs->e2fs_bsize, NULL, &bp) != 0)
+			return (0);
+		level = &info->h_levels[idx + 1];
+		brelse(level->h_bp);
+		level->h_bp = bp;
+		level->h_entry = level->h_entries =
+		    ((struct ext2fs_htree_node *)bp->b_data)->h_entries;
+	}
+
+	return (1);
+}
+
+static uint32_t
+ext2_htree_get_block(struct ext2fs_htree_entry *ep)
+{
+	return (ep->h_blk & 0x00FFFFFF);
+}
+
+static void
+ext2_htree_set_block(struct ext2fs_htree_entry *ep, uint32_t blk)
+{
+	ep->h_blk = blk;
+}
+
+static uint16_t
+ext2_htree_get_count(struct ext2fs_htree_entry *ep)
+{
+	return (((struct ext2fs_htree_count *)(ep))->h_entries_num);
+}
+
+static void
+ext2_htree_set_count(struct ext2fs_htree_entry *ep, uint16_t cnt)
+{
+	((struct ext2fs_htree_count *)(ep))->h_entries_num = cnt;
+}
+
+static uint32_t
+ext2_htree_get_hash(struct ext2fs_htree_entry *ep)
+{
+	return (ep->h_hash);
+}
+
+static uint16_t
+ext2_htree_get_limit(struct ext2fs_htree_entry *ep)
+{
+	return (((struct ext2fs_htree_count *)(ep))->h_entries_max);
+}
+
+static void
+ext2_htree_set_hash(struct ext2fs_htree_entry *ep, uint32_t hash)
+{
+	ep->h_hash = hash;
+}
+
+static void
+ext2_htree_set_limit(struct ext2fs_htree_entry *ep, uint16_t limit)
+{
+	((struct ext2fs_htree_count *)(ep))->h_entries_max = limit;
+}
+
+static void
+ext2_htree_release(struct ext2fs_htree_lookup_info *info)
+{
+	u_int i;
+
+	for (i = 0; i < info->h_levels_num; i++) {
+		struct buf *bp = info->h_levels[i].h_bp;
+
+		if (bp != NULL)
+			brelse(bp);
+	}
+}
+
+static uint32_t
+ext2_htree_root_limit(struct inode *ip, int len)
+{
+	uint32_t space;
+
+	space = ip->i_e2fs->e2fs_bsize - EXT2_DIR_REC_LEN(1) -
+	    EXT2_DIR_REC_LEN(2) - len;
+	return (space / sizeof(struct ext2fs_htree_entry));
+}
+
+static uint32_t
+ext2_htree_node_limit(struct inode *ip)
+{
+	struct m_ext2fs *fs;
+	uint32_t space;
+
+	fs = ip->i_e2fs;
+	space = fs->e2fs_bsize - EXT2_DIR_REC_LEN(0);
+
+	return (space / sizeof(struct ext2fs_htree_entry));
+}
+
+static int
+ext2_htree_find_leaf(struct inode *ip, const char *name, int namelen,
+    uint32_t *hash, uint8_t *hash_ver,
+    struct ext2fs_htree_lookup_info *info)
+{
+	struct vnode *vp;
+	struct ext2fs *fs;
+	struct m_ext2fs *m_fs;
+	struct buf *bp = NULL;
+	struct ext2fs_htree_root *rootp;
+	struct ext2fs_htree_entry *entp, *start, *end, *middle, *found;
+	struct ext2fs_htree_lookup_level *level_info;
+	uint32_t hash_major = 0, hash_minor = 0;
+	uint32_t levels, cnt;
+	uint8_t hash_version;
+
+	if (name == NULL || info == NULL)
+		return (-1);
+
+	vp = ITOV(ip);
+	fs = ip->i_e2fs->e2fs;
+	m_fs = ip->i_e2fs;
+
+	if (ext2_blkatoff(vp, 0, NULL, &bp) != 0)
+		return (-1);
+
+	info->h_levels_num = 1;
+	info->h_levels[0].h_bp = bp;
+	rootp = (struct ext2fs_htree_root *)bp->b_data;
+	if (rootp->h_info.h_hash_version != EXT2_HTREE_LEGACY &&
+	    rootp->h_info.h_hash_version != EXT2_HTREE_HALF_MD4 &&
+	    rootp->h_info.h_hash_version != EXT2_HTREE_TEA)
+		goto error;
+
+	hash_version = rootp->h_info.h_hash_version;
+	if (hash_version <= EXT2_HTREE_TEA)
+		hash_version += m_fs->e2fs_uhash;
+	*hash_ver = hash_version;
+
+	ext2_htree_hash(name, namelen, fs->e3fs_hash_seed,
+	    hash_version, &hash_major, &hash_minor);
+	*hash = hash_major;
+
+	if ((levels = rootp->h_info.h_ind_levels) > 1)
+		goto error;
+
+	entp = (struct ext2fs_htree_entry *)(((char *)&rootp->h_info) +
+	    rootp->h_info.h_info_len);
+
+	if (ext2_htree_get_limit(entp) !=
+	    ext2_htree_root_limit(ip, rootp->h_info.h_info_len))
+		goto error;
+
+	while (1) {
+		cnt = ext2_htree_get_count(entp);
+		if (cnt == 0 || cnt > ext2_htree_get_limit(entp))
+			goto error;
+
+		start = entp + 1;
+		end = entp + cnt - 1;
+		while (start <= end) {
+			middle = start + (end - start) / 2;
+			if (ext2_htree_get_hash(middle) > hash_major)
+				end = middle - 1;
+			else
+				start = middle + 1;
+		}
+		found = start - 1;
+
+		level_info = &(info->h_levels[info->h_levels_num - 1]);
+		level_info->h_bp = bp;
+		level_info->h_entries = entp;
+		level_info->h_entry = found;
+		if (levels == 0)
+			return (0);
+		levels--;
+		if (ext2_blkatoff(vp,
+		    ext2_htree_get_block(found) * m_fs->e2fs_bsize,
+		    NULL, &bp) != 0)
+			goto error;
+		entp = ((struct ext2fs_htree_node *)bp->b_data)->h_entries;
+		info->h_levels_num++;
+		info->h_levels[info->h_levels_num - 1].h_bp = bp;
+	}
+
+error:
+	ext2_htree_release(info);
+	return (-1);
+}
+
+/*
+ * Try to lookup a directory entry in HTree index
+ */
+int
+ext2_htree_lookup(struct inode *ip, const char *name, int namelen,
+    struct buf **bpp, int *entryoffp, doff_t *offp,
+    doff_t *prevoffp, doff_t *endusefulp,
+    struct ext2fs_searchslot *ss)
+{
+	struct vnode *vp;
+	struct ext2fs_htree_lookup_info info;
+	struct ext2fs_htree_entry *leaf_node;
+	struct m_ext2fs *m_fs;
+	struct buf *bp;
+	uint32_t blk;
+	uint32_t dirhash;
+	uint32_t bsize;
+	uint8_t hash_version;
+	int search_next;
+	int found = 0;
+
+	m_fs = ip->i_e2fs;
+	bsize = m_fs->e2fs_bsize;
+	vp = ITOV(ip);
+
+	/* TODO: print error msg because we don't lookup '.' and '..' */
+
+	memset(&info, 0, sizeof(info));
+	if (ext2_htree_find_leaf(ip, name, namelen, &dirhash,
+	    &hash_version, &info))
+		return (-1);
+
+	do {
+		leaf_node = info.h_levels[info.h_levels_num - 1].h_entry;
+		blk = ext2_htree_get_block(leaf_node);
+		if (ext2_blkatoff(vp, blk * bsize, NULL, &bp) != 0) {
+			ext2_htree_release(&info);
+			return (-1);
+		}
+
+		*offp = blk * bsize;
+		*entryoffp = 0;
+		*prevoffp = blk * bsize;
+		*endusefulp = blk * bsize;
+
+		if (ss->slotstatus == NONE) {
+			ss->slotoffset = -1;
+			ss->slotfreespace = 0;
+		}
+
+		if (ext2_search_dirblock(ip, bp->b_data, &found,
+		    name, namelen, entryoffp, offp, prevoffp,
+		    endusefulp, ss) != 0) {
+			brelse(bp);
+			ext2_htree_release(&info);
+			return (-1);
+		}
+
+		if (found) {
+			*bpp = bp;
+			ext2_htree_release(&info);
+			return (0);
+		}
+
+		brelse(bp);
+		search_next = ext2_htree_check_next(ip, dirhash, name, &info);
+	} while (search_next);
+
+	ext2_htree_release(&info);
+	return (ENOENT);
+}
+
+static int
+ext2_htree_append_block(struct vnode *vp, char *data,
+    struct componentname *cnp, uint32_t blksize)
+{
+	struct iovec aiov;
+	struct uio auio;
+	struct inode *dp = VTOI(vp);
+	uint64_t cursize, newsize;
+	int error;
+
+	cursize = roundup(dp->i_size, blksize);
+	newsize = cursize + blksize;
+
+	auio.uio_offset = cursize;
+	auio.uio_resid = blksize;
+	aiov.iov_len = blksize;
+	aiov.iov_base = data;
+	auio.uio_iov = &aiov;
+	auio.uio_iovcnt = 1;
+	auio.uio_rw = UIO_WRITE;
+	auio.uio_segflg = UIO_SYSSPACE;
+	error = VOP_WRITE(vp, &auio, IO_SYNC, cnp->cn_cred);
+	if (!error)
+		dp->i_size = newsize;
+
+	return (error);
+}
+
+static int
+ext2_htree_writebuf(struct ext2fs_htree_lookup_info *info)
+{
+	int i, error;
+
+	for (i = 0; i < info->h_levels_num; i++) {
+		struct buf *bp = info->h_levels[i].h_bp;
+
+		error = bwrite(bp);
+		if (error)
+			return (error);
+	}
+
+	return (0);
+}
+
+static void
+ext2_htree_insert_entry_to_level(struct ext2fs_htree_lookup_level *level,
+    uint32_t hash, uint32_t blk)
+{
+	struct ext2fs_htree_entry *target;
+	int entries_num;
+
+	target = level->h_entry + 1;
+	entries_num = ext2_htree_get_count(level->h_entries);
+
+	memmove(target + 1, target, (char *)(level->h_entries + entries_num) -
+	    (char *)target);
+	ext2_htree_set_block(target, blk);
+	ext2_htree_set_hash(target, hash);
+	ext2_htree_set_count(level->h_entries, entries_num + 1);
+}
+
+/*
+ * Insert an index entry to the index node.
+ */
+static void
+ext2_htree_insert_entry(struct ext2fs_htree_lookup_info *info,
+    uint32_t hash, uint32_t blk)
+{
+	struct ext2fs_htree_lookup_level *level;
+
+	level = &info->h_levels[info->h_levels_num - 1];
+	ext2_htree_insert_entry_to_level(level, hash, blk);
+}
+
+/*
+ * Compare two entry sort descriptors by name hash value.
+ * This is used together with qsort.
+ */
+static int
+ext2_htree_cmp_sort_entry(const void *e1, const void *e2)
+{
+	const struct ext2fs_htree_sort_entry *entry1, *entry2;
+
+	entry1 = (const struct ext2fs_htree_sort_entry *)e1;
+	entry2 = (const struct ext2fs_htree_sort_entry *)e2;
+
+	if (entry1->h_hash < entry2->h_hash)
+		return (-1);
+	if (entry1->h_hash > entry2->h_hash)
+		return (1);
+	return (0);
+}
+
+/*
+ * Append an entry to the end of the directory block.
+ */
+static void
+ext2_append_entry(char *block, uint32_t blksize,
+    struct ext2fs_direct_2 *last_entry,
+    struct ext2fs_direct_2 *new_entry)
+{
+	uint16_t entry_len;
+
+	entry_len = EXT2_DIR_REC_LEN(last_entry->e2d_namlen);
+	last_entry->e2d_reclen = entry_len;
+	last_entry = (struct ext2fs_direct_2 *)((char *)last_entry + entry_len);
+	new_entry->e2d_reclen = block + blksize - (char *)last_entry;
+	memcpy(last_entry, new_entry, EXT2_DIR_REC_LEN(new_entry->e2d_namlen));
+}
+
+/*
+ * Move half of entries from the old directory block to the new one.
+ */
+static int
+ext2_htree_split_dirblock(char *block1, char *block2, uint32_t blksize,
+    uint32_t *hash_seed, uint8_t hash_version,
+    uint32_t *split_hash, struct ext2fs_direct_2 *entry)
+{
+	int entry_cnt = 0;
+	int size = 0;
+	int i, k;
+	uint32_t offset;
+	uint16_t entry_len = 0;
+	uint32_t entry_hash;
+	struct ext2fs_direct_2 *ep, *last;
+	char *dest;
+	struct ext2fs_htree_sort_entry *sort_info;
+
+	ep = (struct ext2fs_direct_2 *)block1;
+	dest = block2;
+	sort_info = (struct ext2fs_htree_sort_entry *)
+	    ((char *)block2 + blksize);
+
+	/*
+	 * Calculate name hash value for the entry which is to be added.
+	 */
+	ext2_htree_hash(entry->e2d_name, entry->e2d_namlen, hash_seed,
+	    hash_version, &entry_hash, NULL);
+
+	/*
+	 * Fill in directory entry sort descriptors.
+	 */
+	while ((char *)ep < block1 + blksize) {
+		if (ep->e2d_ino && ep->e2d_namlen) {
+			entry_cnt++;
+			sort_info--;
+			sort_info->h_size = ep->e2d_reclen;
+			sort_info->h_offset = (char *)ep - block1;
+			ext2_htree_hash(ep->e2d_name, ep->e2d_namlen,
+			    hash_seed, hash_version,
+			    &sort_info->h_hash, NULL);
+		}
+		ep = (struct ext2fs_direct_2 *)
+		    ((char *)ep + ep->e2d_reclen);
+	}
+
+	/*
+	 * Sort directory entry descriptors by name hash value.
+	 */
+	qsort(sort_info, entry_cnt, sizeof(struct ext2fs_htree_sort_entry),
+	    ext2_htree_cmp_sort_entry);
+
+	/*
+	 * Count the number of entries to move to directory block 2.
+	 */
+	for (i = entry_cnt - 1; i >= 0; i--) {
+		if (sort_info[i].h_size + size > blksize / 2)
+			break;
+		size += sort_info[i].h_size;
+	}
+
+	*split_hash = sort_info[i + 1].h_hash;
+
+	/*
+	 * Set collision bit.
+	 */
+	if (*split_hash == sort_info[i].h_hash)
+		*split_hash += 1;
+
+	/*
+	 * Move half of directory entries from block 1 to block 2.
+	 */
+	for (k = i + 1; k < entry_cnt; k++) {
+		ep = (struct ext2fs_direct_2 *)((char *)block1 +
+		    sort_info[k].h_offset);
+		entry_len = EXT2_DIR_REC_LEN(ep->e2d_namlen);
+		memcpy(dest, ep, entry_len);
+		((struct ext2fs_direct_2 *)dest)->e2d_reclen = entry_len;
+		/* Mark directory entry as unused. */
+		ep->e2d_ino = 0;
+		dest += entry_len;
+	}
+	dest -= entry_len;
+
+	/* Shrink directory entries in block 1. */
+	last = (struct ext2fs_direct_2 *)block1;
+	entry_len = 0;
+	for (offset = 0; offset < blksize; ) {
+		ep = (struct ext2fs_direct_2 *)(block1 + offset);
+		offset += ep->e2d_reclen;
+		if (ep->e2d_ino) {
+			last = (struct ext2fs_direct_2 *)
+			    ((char *)last + entry_len);
+			entry_len = EXT2_DIR_REC_LEN(ep->e2d_namlen);
+			memcpy((void *)last, (void *)ep, entry_len);
+			last->e2d_reclen = entry_len;
+		}
+	}
+
+	if (entry_hash >= *split_hash) {
+		/* Add entry to block 2. */
+		ext2_append_entry(block2, blksize,
+		    (struct ext2fs_direct_2 *)dest, entry);
+
+		/* Adjust length field of last entry of block 1. */
+		last->e2d_reclen = block1 + blksize - (char *)last;
+	} else {
+		/* Add entry to block 1. */
+		ext2_append_entry(block1, blksize, last, entry);
+
+		/* Adjust length field of last entry of block 2. */
+		((struct ext2fs_direct_2 *)dest)->e2d_reclen =
+		    block2 + blksize - dest;
+	}
+
+	return (0);
+}
+
+/*
+ * Create an HTree index for a directory
+ */
+int
+ext2_htree_create_index(struct vnode *vp, struct componentname *cnp,
+    struct ext2fs_direct_2 *new_entry)
+{
+	struct buf *bp = NULL;
+	struct inode *dp;
+	struct ext2fs *fs;
+	struct m_ext2fs *m_fs;
+	struct ext2fs_direct_2 *ep, *dotdot;
+	struct ext2fs_htree_root *root;
+	struct ext2fs_htree_lookup_info info;
+	uint32_t blksize, dirlen, split_hash;
+	uint8_t hash_version;
+	char *buf1 = NULL;
+	char *buf2 = NULL;
+	int error = 0;
+
+	dp = VTOI(vp);
+	fs = dp->i_e2fs->e2fs;
+	m_fs = dp->i_e2fs;
+	blksize = m_fs->e2fs_bsize;
+
+	buf1 = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
+	buf2 = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
+
+	if ((error = ext2_blkatoff(vp, 0, NULL, &bp)) != 0)
+		goto out;
+
+	root = (struct ext2fs_htree_root *)bp->b_data;
+	dotdot = (struct ext2fs_direct_2 *)((char *)&(root->h_dotdot));
+	ep = (struct ext2fs_direct_2 *)((char *)dotdot + dotdot->e2d_reclen);
+	dirlen = (char *)root + blksize - (char *)ep;
+	memcpy(buf1, ep, dirlen);
+	ep = (struct ext2fs_direct_2 *)buf1;
+	while ((char *)ep < buf1 + dirlen)
+		ep = (struct ext2fs_direct_2 *)
+		    ((char *)ep + ep->e2d_reclen);
+	ep->e2d_reclen = buf1 + blksize - (char *)ep;
+
+	dp->i_flag |= IN_E3INDEX;
+
+	/*
+	 * Initialize index root.
+	 */
+	dotdot->e2d_reclen = blksize - EXT2_DIR_REC_LEN(1);
+	memset(&root->h_info, 0, sizeof(root->h_info));
+	root->h_info.h_hash_version = fs->e3fs_def_hash_version;
+	root->h_info.h_info_len = sizeof(root->h_info);
+	ext2_htree_set_block(root->h_entries, 1);
+	ext2_htree_set_count(root->h_entries, 1);
+	ext2_htree_set_limit(root->h_entries,
+	    ext2_htree_root_limit(dp, sizeof(root->h_info)));
+
+	memset(&info, 0, sizeof(info));
+	info.h_levels_num = 1;
+	info.h_levels[0].h_entries = root->h_entries;
+	info.h_levels[0].h_entry = root->h_entries;
+
+	hash_version = root->h_info.h_hash_version;
+	if (hash_version <= EXT2_HTREE_TEA)
+		hash_version += m_fs->e2fs_uhash;
+	ext2_htree_split_dirblock(buf1, buf2, blksize, fs->e3fs_hash_seed,
+	    hash_version, &split_hash, new_entry);
+	ext2_htree_insert_entry(&info, split_hash, 2);
+
+	/*
+	 * Write directory block 0.
+	 */
+	if (DOINGASYNC(vp)) {
+		bdwrite(bp);
+		error = 0;
+	} else {
+		error = bwrite(bp);
+	}
+	dp->i_flag |= IN_CHANGE | IN_UPDATE;
+	if (error)
+		goto out;
+
+	/*
+	 * Write directory block 1.
+	 */
+	error = ext2_htree_append_block(vp, buf1, cnp, blksize);
+	if (error)
+		goto out1;
+
+	/*
+	 * Write directory block 2.
+	 */
+	error = ext2_htree_append_block(vp, buf2, cnp, blksize);
+
+	free(buf1, M_TEMP);
+	free(buf2, M_TEMP);
+	return (error);
+out:
+	if (bp != NULL)
+		brelse(bp);
+out1:
+	free(buf1, M_TEMP);
+	free(buf2, M_TEMP);
+	return (error);
+}
+
+/*
+ * Add an entry to the directory using htree index.
+ */
+int
+ext2_htree_add_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry,
+    struct componentname *cnp)
+{
+	struct ext2fs_htree_entry *entries, *leaf_node;
+	struct ext2fs_htree_lookup_info info;
+	struct buf *bp = NULL;
+	struct ext2fs *fs;
+	struct m_ext2fs *m_fs;
+	struct inode *ip;
+	uint16_t ent_num;
+	uint32_t dirhash, split_hash;
+	uint32_t blksize, blknum;
+	uint64_t cursize, dirsize;
+	uint8_t hash_version;
+	char *newdirblock = NULL;
+	char *newidxblock = NULL;
+	struct ext2fs_htree_node *dst_node;
+	struct ext2fs_htree_entry *dst_entries;
+	struct ext2fs_htree_entry *root_entires;
+	struct buf *dst_bp = NULL;
+	int error, write_bp = 0, write_dst_bp = 0, write_info = 0;
+
+	ip = VTOI(dvp);
+	m_fs = ip->i_e2fs;
+	fs = m_fs->e2fs;
+	blksize = m_fs->e2fs_bsize;
+
+	if (ip->i_count != 0)
+		return ext2_add_entry(dvp, entry);
+
+	/* Target directory block is full, split it */
+	memset(&info, 0, sizeof(info));
+	error = ext2_htree_find_leaf(ip, entry->e2d_name, entry->e2d_namlen,
+	    &dirhash, &hash_version, &info);
+	if (error)
+		return (error);
+
+	entries = info.h_levels[info.h_levels_num - 1].h_entries;
+	ent_num = ext2_htree_get_count(entries);
+	if (ent_num == ext2_htree_get_limit(entries)) {
+		/* Split the index node. */
+		root_entires = info.h_levels[0].h_entries;
+		newidxblock = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
+		dst_node = (struct ext2fs_htree_node *)newidxblock;
+		memset(&dst_node->h_fake_dirent, 0,
+		    sizeof(dst_node->h_fake_dirent));
+		dst_node->h_fake_dirent.e2d_reclen = blksize;
+
+		cursize = roundup(ip->i_size, blksize);
+		dirsize = cursize + blksize;
+		blknum = dirsize / blksize - 1;
+
+		error = ext2_htree_append_block(dvp, newidxblock,
+		    cnp, blksize);
+		if (error)
+			goto finish;
+		error = ext2_blkatoff(dvp, cursize, NULL, &dst_bp);
+		if (error)
+			goto finish;
+		dst_node = (struct ext2fs_htree_node *)dst_bp->b_data;
+		dst_entries = dst_node->h_entries;
+
+		if (info.h_levels_num == 2) {
+			uint16_t src_ent_num, dst_ent_num;
+
+			if (ext2_htree_get_count(root_entires) ==
+			    ext2_htree_get_limit(root_entires)) {
+				/* Directory index is full */
+				error = EIO;
+				goto finish;
+			}
+
+			src_ent_num = ent_num / 2;
+			dst_ent_num = ent_num - src_ent_num;
+			split_hash = ext2_htree_get_hash(entries + src_ent_num);
+
+			/* Move half of index entries to the new index node */
+			memcpy(dst_entries, entries + src_ent_num,
+			    dst_ent_num * sizeof(struct ext2fs_htree_entry));
+			ext2_htree_set_count(entries, src_ent_num);
+			ext2_htree_set_count(dst_entries, dst_ent_num);
+			ext2_htree_set_limit(dst_entries,
+			    ext2_htree_node_limit(ip));
+
+			if (info.h_levels[1].h_entry >= entries + src_ent_num) {
+				struct buf *tmp = info.h_levels[1].h_bp;
+
+				info.h_levels[1].h_bp = dst_bp;
+				dst_bp = tmp;
+
+				info.h_levels[1].h_entry =
+				    info.h_levels[1].h_entry -
+				    (entries + src_ent_num) +
+				    dst_entries;
+				info.h_levels[1].h_entries = dst_entries;
+			}
+			ext2_htree_insert_entry_to_level(&info.h_levels[0],
+			    split_hash, blknum);
+
+			/* Write new index node to disk */
+			error = bwrite(dst_bp);
+			ip->i_flag |= IN_CHANGE | IN_UPDATE;
+			if (error)
+				goto finish;
+			write_dst_bp = 1;
+		} else {
+			/* Create second level for htree index */
+			struct ext2fs_htree_root *idx_root;
+
+			memcpy(dst_entries, entries,
+			    ent_num * sizeof(struct ext2fs_htree_entry));
+			ext2_htree_set_limit(dst_entries,
+			    ext2_htree_node_limit(ip));
+
+			idx_root = (struct ext2fs_htree_root *)
+			    info.h_levels[0].h_bp->b_data;
+			idx_root->h_info.h_ind_levels = 1;
+
+			ext2_htree_set_count(entries, 1);
+			ext2_htree_set_block(entries, blknum);
+
+			info.h_levels_num = 2;
+			info.h_levels[1].h_entries = dst_entries;
+			info.h_levels[1].h_entry = info.h_levels[0].h_entry -
+			    info.h_levels[0].h_entries + dst_entries;
+			info.h_levels[1].h_bp = dst_bp;
+			dst_bp = NULL;
+		}
+	}
+
+	leaf_node = info.h_levels[info.h_levels_num - 1].h_entry;
+	blknum = ext2_htree_get_block(leaf_node);
+	error = ext2_blkatoff(dvp, blknum * blksize, NULL, &bp);
+	if (error)
+		goto finish;
+
+	/* Split target directory block */
+	newdirblock = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
+	ext2_htree_split_dirblock((char *)bp->b_data, newdirblock, blksize,
+	    fs->e3fs_hash_seed, hash_version, &split_hash, entry);
+	cursize = roundup(ip->i_size, blksize);
+	dirsize = cursize + blksize;
+	blknum = dirsize / blksize - 1;
+
+	/* Add index entry for the new directory block */
+	ext2_htree_insert_entry(&info, split_hash, blknum);
+
+	/* Write the new directory block to the end of the directory */
+	error = ext2_htree_append_block(dvp, newdirblock, cnp, blksize);
+	if (error)
+		goto finish;
+
+	/* Write the target directory block */
+	error = bwrite(bp);
+	ip->i_flag |= IN_CHANGE | IN_UPDATE;
+	if (error)
+		goto finish;
+	write_bp = 1;
+
+	/* Write the index block */
+	error = ext2_htree_writebuf(&info);
+	if (!error)
+		write_info = 1;
+
+finish:
+	if (dst_bp != NULL && !write_dst_bp)
+		brelse(dst_bp);
+	if (bp != NULL && !write_bp)
+		brelse(bp);
+	if (newdirblock != NULL)
+		free(newdirblock, M_TEMP);
+	if (newidxblock != NULL)
+		free(newidxblock, M_TEMP);
+	if (!write_info)
+		ext2_htree_release(&info);
+	return (error);
+}


Property changes on: trunk/sys/fs/ext2fs/ext2_htree.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/fs/ext2fs/ext2_inode.c
===================================================================
--- trunk/sys/fs/ext2fs/ext2_inode.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2_inode.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  *  modified for Lites 1.1
  *
@@ -33,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)ffs_inode.c	8.5 (Berkeley) 12/30/93
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_inode.c 311232 2017-01-04 02:43:33Z pfg $
  */
 
 #include <sys/param.h>
@@ -43,6 +44,7 @@
 #include <sys/buf.h>
 #include <sys/vnode.h>
 #include <sys/malloc.h>
+#include <sys/rwlock.h>
 
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
@@ -53,8 +55,8 @@
 #include <fs/ext2fs/fs.h>
 #include <fs/ext2fs/ext2_extern.h>
 
-static int ext2_indirtrunc(struct inode *, int32_t, int32_t, int32_t, int,
-	    long *);
+static int ext2_indirtrunc(struct inode *, daddr_t, daddr_t,
+	    daddr_t, int, e4fs_daddr_t *);
 
 /*
  * Update the access, modified, and inode change times as specified by the
@@ -80,11 +82,11 @@
 		return (0);
 	ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED);
 	fs = ip->i_e2fs;
-	if(fs->e2fs_ronly)
+	if (fs->e2fs_ronly)
 		return (0);
 	if ((error = bread(ip->i_devvp,
 	    fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
-		(int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
+	    (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
 		brelse(bp);
 		return (error);
 	}
@@ -114,25 +116,29 @@
 	struct inode *oip;
 	int32_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
 	uint32_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
-	struct bufobj *bo;
 	struct m_ext2fs *fs;
 	struct buf *bp;
 	int offset, size, level;
-	long count, nblocks, blocksreleased = 0;
+	e4fs_daddr_t count, nblocks, blocksreleased = 0;
 	int error, i, allerror;
 	off_t osize;
+#ifdef INVARIANTS
+	struct bufobj *bo;
+#endif
 
 	oip = VTOI(ovp);
+#ifdef INVARIANTS
 	bo = &ovp->v_bufobj;
+#endif
 
-	ASSERT_VOP_LOCKED(vp, "ext2_truncate");	
+	ASSERT_VOP_LOCKED(vp, "ext2_truncate");
 
 	if (length < 0)
-	    return (EINVAL);
+		return (EINVAL);
 
 	if (ovp->v_type == VLNK &&
 	    oip->i_size < ovp->v_mount->mnt_maxsymlinklen) {
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 		if (length != 0)
 			panic("ext2_truncate: partial truncate of symlink");
 #endif
@@ -223,14 +229,18 @@
 	 * will be returned to the free list.  lastiblock values are also
 	 * normalized to -1 for calls to ext2_indirtrunc below.
 	 */
-	bcopy((caddr_t)&oip->i_db[0], (caddr_t)oldblks, sizeof(oldblks));
-	for (level = TRIPLE; level >= SINGLE; level--)
+	for (level = TRIPLE; level >= SINGLE; level--) {
+		oldblks[NDADDR + level] = oip->i_ib[level];
 		if (lastiblock[level] < 0) {
 			oip->i_ib[level] = 0;
 			lastiblock[level] = -1;
 		}
-	for (i = NDADDR - 1; i > lastblock; i--)
-		oip->i_db[i] = 0;
+	}
+	for (i = 0; i < NDADDR; i++) {
+		oldblks[i] = oip->i_db[i];
+		if (i > lastblock)
+			oip->i_db[i] = 0;
+	}
 	oip->i_flag |= IN_CHANGE | IN_UPDATE;
 	allerror = ext2_update(ovp, !DOINGASYNC(ovp));
 
@@ -240,14 +250,20 @@
 	 * Note that we save the new block configuration so we can check it
 	 * when we are done.
 	 */
-	bcopy((caddr_t)&oip->i_db[0], (caddr_t)newblks, sizeof(newblks));
-	bcopy((caddr_t)oldblks, (caddr_t)&oip->i_db[0], sizeof(oldblks));
+	for (i = 0; i < NDADDR; i++) {
+		newblks[i] = oip->i_db[i];
+		oip->i_db[i] = oldblks[i];
+	}
+	for (i = 0; i < NIADDR; i++) {
+		newblks[NDADDR + i] = oip->i_ib[i];
+		oip->i_ib[i] = oldblks[NDADDR + i];
+	}
 	oip->i_size = osize;
-	error = vtruncbuf(ovp, cred, td, length, (int)fs->e2fs_bsize);
+	error = vtruncbuf(ovp, cred, length, (int)fs->e2fs_bsize);
 	if (error && (allerror == 0))
 		allerror = error;
 	vnode_pager_setsize(ovp, length);
-	
+
 	/*
 	 * Indirect blocks first.
 	 */
@@ -318,7 +334,7 @@
 		}
 	}
 done:
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 	for (level = SINGLE; level <= TRIPLE; level++)
 		if (newblks[NDADDR + level] != oip->i_ib[level])
 			panic("itrunc1");
@@ -330,7 +346,7 @@
 	    bo->bo_clean.bv_cnt != 0))
 		panic("itrunc3");
 	BO_UNLOCK(bo);
-#endif /* DIAGNOSTIC */
+#endif	/* INVARIANTS */
 	/*
 	 * Put back the real size.
 	 */
@@ -355,16 +371,16 @@
  */
 
 static int
-ext2_indirtrunc(struct inode *ip, int32_t lbn, int32_t dbn, int32_t lastbn,
-    int level, long *countp)
+ext2_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn,
+    daddr_t lastbn, int level, e4fs_daddr_t *countp)
 {
 	struct buf *bp;
 	struct m_ext2fs *fs = ip->i_e2fs;
 	struct vnode *vp;
-	int32_t *bap, *copy, nb, nlbn, last;
-	long blkcount, factor;
-	int i, nblocks, blocksreleased = 0;
-	int error = 0, allerror = 0;
+	e2fs_daddr_t *bap, *copy;
+	int i, nblocks, error = 0, allerror = 0;
+	e2fs_lbn_t nb, nlbn, last;
+	e4fs_daddr_t blkcount, factor, blocksreleased = 0;
 
 	/*
 	 * Calculate index in current block of last
@@ -403,12 +419,11 @@
 		*countp = 0;
 		return (error);
 	}
-
-	bap = (int32_t *)bp->b_data;
+	bap = (e2fs_daddr_t *)bp->b_data;
 	copy = malloc(fs->e2fs_bsize, M_TEMP, M_WAITOK);
 	bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->e2fs_bsize);
 	bzero((caddr_t)&bap[last + 1],
-	  (u_int)(NINDIR(fs) - (last + 1)) * sizeof(int32_t));
+	    (NINDIR(fs) - (last + 1)) * sizeof(e2fs_daddr_t));
 	if (last == -1)
 		bp->b_flags |= B_INVAL;
 	if (DOINGASYNC(vp)) {
@@ -488,7 +503,7 @@
 	 * so that it can be reused immediately.
 	 */
 	if (ip->i_mode == 0)
-		vrecycle(vp, td);
+		vrecycle(vp);
 	return (error);
 }
 

Modified: trunk/sys/fs/ext2fs/ext2_inode_cnv.c
===================================================================
--- trunk/sys/fs/ext2fs/ext2_inode_cnv.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2_inode_cnv.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1995 The University of Utah and
  * the Computer Systems Laboratory at the University of Utah (CSL).
@@ -19,7 +20,7 @@
  * improvements that they make and grant CSL redistribution rights.
  *
  *      Utah $Hdr$
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_inode_cnv.c 320841 2017-07-09 15:14:22Z pfg $
  */
 
 /*
@@ -32,6 +33,7 @@
 #include <sys/stat.h>
 #include <sys/vnode.h>
 
+#include <fs/ext2fs/fs.h>
 #include <fs/ext2fs/inode.h>
 #include <fs/ext2fs/ext2fs.h>
 #include <fs/ext2fs/ext2_dinode.h>
@@ -40,28 +42,42 @@
 #define XTIME_TO_NSEC(x)	((x & EXT3_NSEC_MASK) >> 2)
 #define NSEC_TO_XTIME(t)	(le32toh(t << 2) & EXT3_NSEC_MASK)
 
+#ifdef EXT2FS_DEBUG
 void
 ext2_print_inode(struct inode *in)
 {
 	int i;
+	struct ext4_extent_header *ehp;
+	struct ext4_extent *ep;
 
-	printf( "Inode: %5d", in->i_number);
-	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("Inode: %5ju", (uintmax_t)in->i_number);
+	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: %5u Group: %5u  Size: %ju\n",
+	    in->i_uid, in->i_gid, (uintmax_t)in->i_size);
+	printf("Links: %3d Blockcount: %ju\n",
+	    in->i_nlink, (uintmax_t)in->i_blocks);
+	printf("ctime: 0x%x", in->i_ctime);
+	printf("atime: 0x%x", in->i_atime);
+	printf("mtime: 0x%x", in->i_mtime);
+	if (E2DI_HAS_XTIME(in))
+		printf("crtime %#x ", in->i_birthtime);
+	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");
+	printf("Extents:\n");
+	ehp = (struct ext4_extent_header *)in->i_db;
+	printf("Header (magic 0x%x entries %d max %d depth %d gen %d)\n",
+	    ehp->eh_magic, ehp->eh_ecount, ehp->eh_max, ehp->eh_depth,
+	    ehp->eh_gen);
+	ep = (struct ext4_extent *)(char *)(ehp + 1);
+	printf("Index (blk %d len %d start_lo %d start_hi %d)\n", ep->e_blk,
+	    ep->e_len, ep->e_start_lo, ep->e_start_hi);
+	printf("\n");
 }
+#endif	/* EXT2FS_DEBUG */
 
 /*
  *	raw ext2 inode to inode
@@ -69,14 +85,15 @@
 void
 ext2_ei2i(struct ext2fs_dinode *ei, struct inode *ip)
 {
-        int i;
+	int i;
 
 	ip->i_nlink = ei->e2di_nlink;
-	/* 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.
-	*/
+	/*
+	 * 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.
+	 */
 	ip->i_mode = ei->e2di_nlink ? ei->e2di_mode : 0;
 	ip->i_size = ei->e2di_size;
 	if (S_ISREG(ip->i_mode))
@@ -95,14 +112,23 @@
 	ip->i_flags |= (ei->e2di_flags & EXT2_APPEND) ? SF_APPEND : 0;
 	ip->i_flags |= (ei->e2di_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
 	ip->i_flags |= (ei->e2di_flags & EXT2_NODUMP) ? UF_NODUMP : 0;
+	ip->i_flag |= (ei->e2di_flags & EXT3_INDEX) ? IN_E3INDEX : 0;
+	ip->i_flag |= (ei->e2di_flags & EXT4_EXTENTS) ? IN_E4EXTENTS : 0;
 	ip->i_blocks = ei->e2di_nblock;
+	if (E2DI_HAS_HUGE_FILE(ip)) {
+		ip->i_blocks |= (uint64_t)ei->e2di_nblock_high << 32;
+		if (ei->e2di_flags & EXT4_HUGE_FILE)
+			ip->i_blocks = fsbtodb(ip->i_e2fs, ip->i_blocks);
+	}
 	ip->i_gen = ei->e2di_gen;
 	ip->i_uid = ei->e2di_uid;
 	ip->i_gid = ei->e2di_gid;
+	ip->i_uid |= (uint32_t)ei->e2di_uid_high << 16;
+	ip->i_gid |= (uint32_t)ei->e2di_gid_high << 16;
 	/* XXX use memcpy */
-	for(i = 0; i < NDADDR; i++)
+	for (i = 0; i < NDADDR; i++)
 		ip->i_db[i] = ei->e2di_blocks[i];
-	for(i = 0; i < NIADDR; i++)
+	for (i = 0; i < NIADDR; i++)
 		ip->i_ib[i] = ei->e2di_blocks[EXT2_NDIR_BLOCKS + i];
 }
 
@@ -116,9 +142,9 @@
 
 	ei->e2di_mode = ip->i_mode;
 	ei->e2di_nlink = ip->i_nlink;
-	/* 
-	   Godmar thinks: if dtime is nonzero, ext2 says this inode
-	   has been deleted, this would correspond to a zero link count
+	/*
+	 * Godmar thinks: if dtime is nonzero, ext2 says this inode has been
+	 * deleted, this would correspond to a zero link count
 	 */
 	ei->e2di_dtime = ei->e2di_nlink ? 0 : ip->i_mtime;
 	ei->e2di_size = ip->i_size;
@@ -134,18 +160,22 @@
 		ei->e2di_crtime = ip->i_birthtime;
 		ei->e2di_crtime_extra = NSEC_TO_XTIME(ip->i_birthnsec);
 	}
-	ei->e2di_flags = ip->i_flags;
 	ei->e2di_flags = 0;
-	ei->e2di_flags |= (ip->i_flags & SF_APPEND) ? EXT2_APPEND: 0;
-	ei->e2di_flags |= (ip->i_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
-	ei->e2di_flags |= (ip->i_flags & UF_NODUMP) ? EXT2_NODUMP: 0;
-	ei->e2di_nblock = ip->i_blocks;
+	ei->e2di_flags |= (ip->i_flags & SF_APPEND) ? EXT2_APPEND : 0;
+	ei->e2di_flags |= (ip->i_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
+	ei->e2di_flags |= (ip->i_flags & UF_NODUMP) ? EXT2_NODUMP : 0;
+	ei->e2di_flags |= (ip->i_flag & IN_E3INDEX) ? EXT3_INDEX : 0;
+	ei->e2di_flags |= (ip->i_flag & IN_E4EXTENTS) ? EXT4_EXTENTS : 0;
+	ei->e2di_nblock = ip->i_blocks & 0xffffffff;
+	ei->e2di_nblock_high = ip->i_blocks >> 32 & 0xffff;
 	ei->e2di_gen = ip->i_gen;
-	ei->e2di_uid = ip->i_uid;
-	ei->e2di_gid = ip->i_gid;
+	ei->e2di_uid = ip->i_uid & 0xffff;
+	ei->e2di_uid_high = ip->i_uid >> 16 & 0xffff;
+	ei->e2di_gid = ip->i_gid & 0xffff;
+	ei->e2di_gid_high = ip->i_gid >> 16 & 0xffff;
 	/* XXX use memcpy */
-	for(i = 0; i < NDADDR; i++)
+	for (i = 0; i < NDADDR; i++)
 		ei->e2di_blocks[i] = ip->i_db[i];
-	for(i = 0; i < NIADDR; i++)
+	for (i = 0; i < NIADDR; i++)
 		ei->e2di_blocks[EXT2_NDIR_BLOCKS + i] = ip->i_ib[i];
 }

Modified: trunk/sys/fs/ext2fs/ext2_lookup.c
===================================================================
--- trunk/sys/fs/ext2fs/ext2_lookup.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2_lookup.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  *  modified for Lites 1.1
  *
@@ -38,7 +39,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)ufs_lookup.c	8.6 (Berkeley) 4/1/94
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_lookup.c 332750 2018-04-19 02:50:15Z pfg $
  */
 
 #include <sys/param.h>
@@ -62,7 +63,7 @@
 #include <fs/ext2fs/ext2_dir.h>
 #include <fs/ext2fs/ext2_extern.h>
 
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 static int dirchk = 1;
 #else
 static int dirchk = 0;
@@ -113,65 +114,84 @@
 
 static int	ext2_dirbadentry(struct vnode *dp, struct ext2fs_direct_2 *de,
 		    int entryoffsetinblock);
+static int	ext2_is_dot_entry(struct componentname *cnp);
 static int	ext2_lookup_ino(struct vnode *vdp, struct vnode **vpp,
 		    struct componentname *cnp, ino_t *dd_ino);
 
+static int
+ext2_is_dot_entry(struct componentname *cnp)
+{
+	if (cnp->cn_namelen <= 2 && cnp->cn_nameptr[0] == '.' &&
+	    (cnp->cn_nameptr[1] == '.' || cnp->cn_nameptr[1] == '\0'))
+		return (1);
+	return (0);
+}
+
 /*
  * Vnode op for reading directories.
- *
- * This function has to convert directory entries from the on-disk
- * format to the format defined by <sys/dirent.h>.  Unfortunately, the
- * conversion will blow up some entries by four bytes, so it can't be
- * done in place.  Instead, the conversion is done entry by entry and
- * the converted entry is sent via uiomove.
- *
- * XXX allocate a buffer, convert as many entries as possible, then send
- * the whole buffer to uiomove
  */
 int
 ext2_readdir(struct vop_readdir_args *ap)
 {
+	struct vnode *vp = ap->a_vp;
 	struct uio *uio = ap->a_uio;
-	int count, error;
-
-	struct ext2fs_direct_2 *edp, *dp;
+	struct buf *bp;
+	struct inode *ip;
+	struct ext2fs_direct_2 *dp, *edp;
+	u_long *cookies;
+	struct dirent dstdp;
+	off_t offset, startoffset;
+	size_t readcnt, skipcnt;
+	ssize_t startresid;
 	int ncookies;
-	struct dirent dstdp;
-	struct uio auio;
-	struct iovec aiov;
-	caddr_t dirbuf;
 	int DIRBLKSIZ = VTOI(ap->a_vp)->i_e2fs->e2fs_bsize;
-	int readcnt;
-	off_t startoffset = uio->uio_offset;
+	int error;
 
-	count = uio->uio_resid;
-	/*
-	 * Avoid complications for partial directory entries by adjusting
-	 * the i/o to end at a block boundary.  Don't give up (like ufs
-	 * does) if the initial adjustment gives a negative count, since
-	 * many callers don't supply a large enough buffer.  The correct
-	 * size is a little larger than DIRBLKSIZ to allow for expansion
-	 * of directory entries, but some callers just use 512.
-	 */
-	count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
-	if (count <= 0)
-		count += DIRBLKSIZ;
-	auio = *uio;
-	auio.uio_iov = &aiov;
-	auio.uio_iovcnt = 1;
-	auio.uio_resid = count;
-	auio.uio_segflg = UIO_SYSSPACE;
-	aiov.iov_len = count;
-	dirbuf = malloc(count, M_TEMP, M_WAITOK);
-	aiov.iov_base = dirbuf;
-	error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
-	if (error == 0) {
-		readcnt = count - auio.uio_resid;
-		edp = (struct ext2fs_direct_2 *)&dirbuf[readcnt];
+	if (uio->uio_offset < 0)
+		return (EINVAL);
+	ip = VTOI(vp);
+	if (ap->a_ncookies != NULL) {
+		if (uio->uio_resid < 0)
+			ncookies = 0;
+		else
+			ncookies = uio->uio_resid;
+		if (uio->uio_offset >= ip->i_size)
+			ncookies = 0;
+		else if (ip->i_size - uio->uio_offset < ncookies)
+			ncookies = ip->i_size - uio->uio_offset;
+		ncookies = ncookies / (offsetof(struct ext2fs_direct_2,
+		    e2d_namlen) + 4) + 1;
+		cookies = malloc(ncookies * sizeof(*cookies), M_TEMP, M_WAITOK);
+		*ap->a_ncookies = ncookies;
+		*ap->a_cookies = cookies;
+	} else {
 		ncookies = 0;
-		bzero(&dstdp, offsetof(struct dirent, d_name));
-		for (dp = (struct ext2fs_direct_2 *)dirbuf;
-		    !error && uio->uio_resid > 0 && dp < edp; ) {
+		cookies = NULL;
+	}
+	offset = startoffset = uio->uio_offset;
+	startresid = uio->uio_resid;
+	error = 0;
+	while (error == 0 && uio->uio_resid > 0 &&
+	    uio->uio_offset < ip->i_size) {
+		error = ext2_blkatoff(vp, uio->uio_offset, NULL, &bp);
+		if (error)
+			break;
+		if (bp->b_offset + bp->b_bcount > ip->i_size)
+			readcnt = ip->i_size - bp->b_offset;
+		else
+			readcnt = bp->b_bcount;
+		skipcnt = (size_t)(uio->uio_offset - bp->b_offset) &
+		    ~(size_t)(DIRBLKSIZ - 1);
+		offset = bp->b_offset + skipcnt;
+		dp = (struct ext2fs_direct_2 *)&bp->b_data[skipcnt];
+		edp = (struct ext2fs_direct_2 *)&bp->b_data[readcnt];
+		while (error == 0 && uio->uio_resid > 0 && dp < edp) {
+			if (dp->e2d_reclen <= offsetof(struct ext2fs_direct_2,
+			    e2d_namlen) || (caddr_t)dp + dp->e2d_reclen >
+			    (caddr_t)edp) {
+				error = EIO;
+				break;
+			}
 			/*-
 			 * "New" ext2fs directory entries differ in 3 ways
 			 * from ufs on-disk ones:
@@ -188,57 +208,60 @@
 			 * because ext2fs uses a machine-independent disk
 			 * layout.
 			 */
+			dstdp.d_namlen = dp->e2d_namlen;
+			dstdp.d_type = FTTODT(dp->e2d_type);
+			if (offsetof(struct ext2fs_direct_2, e2d_namlen) +
+			    dstdp.d_namlen > dp->e2d_reclen) {
+				error = EIO;
+				break;
+			}
+			if (offset < startoffset || dp->e2d_ino == 0)
+				goto nextentry;
 			dstdp.d_fileno = dp->e2d_ino;
-			dstdp.d_type = FTTODT(dp->e2d_type);
-			dstdp.d_namlen = dp->e2d_namlen;
 			dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp);
 			bcopy(dp->e2d_name, dstdp.d_name, dstdp.d_namlen);
-			bzero(dstdp.d_name + dstdp.d_namlen,
-			    dstdp.d_reclen - offsetof(struct dirent, d_name) -
-			    dstdp.d_namlen);
-
-			if (dp->e2d_reclen > 0) {
-				if(dstdp.d_reclen <= uio->uio_resid) {
-					/* advance dp */
-					dp = (struct ext2fs_direct_2 *)
-					    ((char *)dp + dp->e2d_reclen);
-					error =
-					  uiomove(&dstdp, dstdp.d_reclen, uio);
-					if (!error)
-						ncookies++;
-				} else
-					break;
-			} else {
-				error = EIO;
+			dstdp.d_name[dstdp.d_namlen] = '\0';
+			if (dstdp.d_reclen > uio->uio_resid) {
+				if (uio->uio_resid == startresid)
+					error = EINVAL;
+				else
+					error = EJUSTRETURN;
 				break;
 			}
-		}
-		/* we need to correct uio_offset */
-		uio->uio_offset = startoffset + (caddr_t)dp - dirbuf;
-
-		if (!error && ap->a_ncookies != NULL) {
-			u_long *cookiep, *cookies, *ecookies;
-			off_t off;
-
-			if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
-				panic("ext2_readdir: unexpected uio from NFS server");
-			cookies = malloc(ncookies * sizeof(u_long), M_TEMP,
-			       M_WAITOK);
-			off = startoffset;
-			for (dp = (struct ext2fs_direct_2 *)dirbuf,
-			     cookiep = cookies, ecookies = cookies + ncookies;
-			     cookiep < ecookies;
-			     dp = (struct ext2fs_direct_2 *)((caddr_t) dp + dp->e2d_reclen)) {
-				off += dp->e2d_reclen;
-				*cookiep++ = (u_long) off;
+			/* Advance dp. */
+			error = uiomove((caddr_t)&dstdp, dstdp.d_reclen, uio);
+			if (error)
+				break;
+			if (cookies != NULL) {
+				KASSERT(ncookies > 0,
+				    ("ext2_readdir: cookies buffer too small"));
+				*cookies = offset + dp->e2d_reclen;
+				cookies++;
+				ncookies--;
 			}
-			*ap->a_ncookies = ncookies;
-			*ap->a_cookies = cookies;
+nextentry:
+			offset += dp->e2d_reclen;
+			dp = (struct ext2fs_direct_2 *)((caddr_t)dp +
+			    dp->e2d_reclen);
 		}
+		bqrelse(bp);
+		uio->uio_offset = offset;
 	}
-	free(dirbuf, M_TEMP);
-	if (ap->a_eofflag)
-		*ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset;
+	/* We need to correct uio_offset. */
+	uio->uio_offset = offset;
+	if (error == EJUSTRETURN)
+		error = 0;
+	if (ap->a_ncookies != NULL) {
+		if (error == 0) {
+			ap->a_ncookies -= ncookies;
+		} else {
+			free(*ap->a_cookies, M_TEMP);
+			*ap->a_ncookies = 0;
+			*ap->a_cookies = NULL;
+		}
+	}
+	if (error == 0 && ap->a_eofflag)
+		*ap->a_eofflag = ip->i_size <= uio->uio_offset;
 	return (error);
 }
 
@@ -287,13 +310,9 @@
 	struct buf *bp;			/* a buffer of directory entries */
 	struct ext2fs_direct_2 *ep;	/* the current directory entry */
 	int entryoffsetinblock;		/* offset of ep in bp's buffer */
-	enum {NONE, COMPACT, FOUND} slotstatus;
-	doff_t slotoffset;		/* offset of area with free space */
-	int slotsize;			/* size of area at slotoffset */
+	struct ext2fs_searchslot ss;
 	doff_t i_diroff;		/* cached i_diroff value */
 	doff_t i_offset;		/* cached i_offset value */
-	int slotfreespace;		/* amount of space free in slot */
-	int slotneeded;			/* size of the entry we're seeking */
 	int numdirpasses;		/* strategy for directory search */
 	doff_t endsearch;		/* offset to end directory search */
 	doff_t prevoff;			/* prev entry dp->i_offset */
@@ -301,14 +320,15 @@
 	struct vnode *tdp;		/* returned by VFS_VGET */
 	doff_t enduseful;		/* pointer past last used dir slot */
 	u_long bmask;			/* block offset mask */
-	int namlen, error;
+	int error;
 	struct ucred *cred = cnp->cn_cred;
 	int flags = cnp->cn_flags;
 	int nameiop = cnp->cn_nameiop;
 	ino_t ino, ino1;
 	int ltype;
+	int entry_found = 0;
 
-	int	DIRBLKSIZ = VTOI(vdp)->i_e2fs->e2fs_bsize;
+	int DIRBLKSIZ = VTOI(vdp)->i_e2fs->e2fs_bsize;
 
 	if (vpp != NULL)
 		*vpp = NULL;
@@ -317,30 +337,55 @@
 	bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
 restart:
 	bp = NULL;
-	slotoffset = -1;
+	ss.slotoffset = -1;
 
 	/*
 	 * We now have a segment name to search for, and a directory to search.
-	 */
-
-	/*
+	 *
 	 * Suppress search for slots unless creating
 	 * file and at end of pathname, in which case
 	 * we watch for a place to put the new file in
 	 * case it doesn't already exist.
 	 */
-	ino = 0;
 	i_diroff = dp->i_diroff;
-	slotstatus = FOUND;
-	slotfreespace = slotsize = slotneeded = 0;
+	ss.slotstatus = FOUND;
+	ss.slotfreespace = ss.slotsize = ss.slotneeded = 0;
 	if ((nameiop == CREATE || nameiop == RENAME) &&
 	    (flags & ISLASTCN)) {
-		slotstatus = NONE;
-		slotneeded = EXT2_DIR_REC_LEN(cnp->cn_namelen);
-		/* was
-		slotneeded = (sizeof(struct direct) - MAXNAMLEN +
-			cnp->cn_namelen + 3) &~ 3; */
+		ss.slotstatus = NONE;
+		ss.slotneeded = EXT2_DIR_REC_LEN(cnp->cn_namelen);
+		/*
+		 * was ss.slotneeded = (sizeof(struct direct) - MAXNAMLEN +
+		 * cnp->cn_namelen + 3) &~ 3;
+		 */
 	}
+	/*
+	 * Try to lookup dir entry using htree directory index.
+	 *
+	 * If we got an error or we want to find '.' or '..' entry,
+	 * we will fall back to linear search.
+	 */
+	if (!ext2_is_dot_entry(cnp) && ext2_htree_has_idx(dp)) {
+		numdirpasses = 1;
+		entryoffsetinblock = 0;
+		switch (ext2_htree_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen,
+		    &bp, &entryoffsetinblock, &i_offset, &prevoff,
+		    &enduseful, &ss)) {
+		case 0:
+			ep = (struct ext2fs_direct_2 *)((char *)bp->b_data +
+			    (i_offset & bmask));
+			goto foundentry;
+		case ENOENT:
+			i_offset = roundup2(dp->i_size, DIRBLKSIZ);
+			goto notfound;
+		default:
+			/*
+			 * Something failed; just fallback to do a linear
+			 * search.
+			 */
+			break;
+		}
+	}
 
 	/*
 	 * If there is cached information on a previous search of
@@ -376,96 +421,38 @@
 		/*
 		 * If necessary, get the next directory block.
 		 */
-		if ((i_offset & bmask) == 0) {
-			if (bp != NULL)
-				brelse(bp);
-			if ((error =
-			    ext2_blkatoff(vdp, (off_t)i_offset, NULL,
-			    &bp)) != 0)
-				return (error);
-			entryoffsetinblock = 0;
-		}
+		if (bp != NULL)
+			brelse(bp);
+		error = ext2_blkatoff(vdp, (off_t)i_offset, NULL, &bp);
+		if (error != 0)
+			return (error);
+		entryoffsetinblock = 0;
 		/*
 		 * If still looking for a slot, and at a DIRBLKSIZE
 		 * boundary, have to start looking for free space again.
 		 */
-		if (slotstatus == NONE &&
+		if (ss.slotstatus == NONE &&
 		    (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) {
-			slotoffset = -1;
-			slotfreespace = 0;
+			ss.slotoffset = -1;
+			ss.slotfreespace = 0;
 		}
-		/*
-		 * Get pointer to next entry.
-		 * Full validation checks are slow, so we only check
-		 * enough to insure forward progress through the
-		 * directory. Complete checks can be run by setting
-		 * "vfs.e2fs.dirchk" to be true.
-		 */
-		ep = (struct ext2fs_direct_2 *)
-			((char *)bp->b_data + entryoffsetinblock);
-		if (ep->e2d_reclen == 0 ||
-		    (dirchk && ext2_dirbadentry(vdp, ep, entryoffsetinblock))) {
-			int i;
-			ext2_dirbad(dp, i_offset, "mangled entry");
-			i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
-			i_offset += i;
-			entryoffsetinblock += i;
-			continue;
+		error = ext2_search_dirblock(dp, bp->b_data, &entry_found,
+		    cnp->cn_nameptr, cnp->cn_namelen,
+		    &entryoffsetinblock, &i_offset, &prevoff,
+		    &enduseful, &ss);
+		if (error != 0) {
+			brelse(bp);
+			return (error);
 		}
-
-		/*
-		 * If an appropriate sized slot has not yet been found,
-		 * check to see if one is available. Also accumulate space
-		 * in the current block so that we can determine if
-		 * compaction is viable.
-		 */
-		if (slotstatus != FOUND) {
-			int size = ep->e2d_reclen;
-
-			if (ep->e2d_ino != 0)
-				size -= EXT2_DIR_REC_LEN(ep->e2d_namlen);
-			if (size > 0) {
-				if (size >= slotneeded) {
-					slotstatus = FOUND;
-					slotoffset = i_offset;
-					slotsize = ep->e2d_reclen;
-				} else if (slotstatus == NONE) {
-					slotfreespace += size;
-					if (slotoffset == -1)
-						slotoffset = i_offset;
-					if (slotfreespace >= slotneeded) {
-						slotstatus = COMPACT;
-						slotsize = i_offset +
-						      ep->e2d_reclen - slotoffset;
-					}
-				}
-			}
+		if (entry_found) {
+			ep = (struct ext2fs_direct_2 *)((char *)bp->b_data +
+			    (entryoffsetinblock & bmask));
+foundentry:
+			ino = ep->e2d_ino;
+			goto found;
 		}
-
-		/*
-		 * Check for a name match.
-		 */
-		if (ep->e2d_ino) {
-			namlen = ep->e2d_namlen;
-			if (namlen == cnp->cn_namelen &&
-			    !bcmp(cnp->cn_nameptr, ep->e2d_name,
-				(unsigned)namlen)) {
-				/*
-				 * Save directory entry's inode number and
-				 * reclen in ndp->ni_ufs area, and release
-				 * directory buffer.
-				 */
-				ino = ep->e2d_ino;
-				goto found;
-			}
-		}
-		prevoff = i_offset;
-		i_offset += ep->e2d_reclen;
-		entryoffsetinblock += ep->e2d_reclen;
-		if (ep->e2d_ino)
-			enduseful = i_offset;
 	}
-/* notfound: */
+notfound:
 	/*
 	 * If we started in the middle of the directory and failed
 	 * to find our target, we must check the beginning as well.
@@ -476,7 +463,6 @@
 		endsearch = i_diroff;
 		goto searchloop;
 	}
-	dp->i_offset = i_offset;
 	if (bp != NULL)
 		brelse(bp);
 	/*
@@ -501,18 +487,17 @@
 		 * can be put in the range from dp->i_offset to
 		 * dp->i_offset + dp->i_count.
 		 */
-		if (slotstatus == NONE) {
+		if (ss.slotstatus == NONE) {
 			dp->i_offset = roundup2(dp->i_size, DIRBLKSIZ);
 			dp->i_count = 0;
 			enduseful = dp->i_offset;
 		} else {
-			dp->i_offset = slotoffset;
-			dp->i_count = slotsize;
-			if (enduseful < slotoffset + slotsize)
-				enduseful = slotoffset + slotsize;
+			dp->i_offset = ss.slotoffset;
+			dp->i_count = ss.slotsize;
+			if (enduseful < ss.slotoffset + ss.slotsize)
+				enduseful = ss.slotoffset + ss.slotsize;
 		}
 		dp->i_endoff = roundup2(enduseful, DIRBLKSIZ);
-		dp->i_flag |= IN_CHANGE | IN_UPDATE;
 		/*
 		 * We return with the directory locked, so that
 		 * the parameters we set up above will still be
@@ -532,7 +517,7 @@
 	/*
 	 * Insert name into cache (as non-existent) if appropriate.
 	 */
-	if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
+	if ((cnp->cn_flags & MAKEENTRY) != 0)
 		cache_enter(vdp, NULL, cnp);
 	return (ENOENT);
 
@@ -546,9 +531,9 @@
 	 * of this entry.
 	 */
 	if (entryoffsetinblock + EXT2_DIR_REC_LEN(ep->e2d_namlen)
-		> dp->i_size) {
+	    > dp->i_size) {
 		ext2_dirbad(dp, i_offset, "i_size too small");
-		dp->i_size = entryoffsetinblock+EXT2_DIR_REC_LEN(ep->e2d_namlen);
+		dp->i_size = entryoffsetinblock + EXT2_DIR_REC_LEN(ep->e2d_namlen);
 		dp->i_flag |= IN_CHANGE | IN_UPDATE;
 	}
 	brelse(bp);
@@ -560,12 +545,13 @@
 	 */
 	if ((flags & ISLASTCN) && nameiop == LOOKUP)
 		dp->i_diroff = i_offset &~ (DIRBLKSIZ - 1);
-	dp->i_offset = i_offset;
 	/*
 	 * If deleting, and at end of pathname, return
 	 * parameters which can be used to remove file.
 	 */
 	if (nameiop == DELETE && (flags & ISLASTCN)) {
+		if (flags & LOCKPARENT)
+			ASSERT_VOP_ELOCKED(vdp, __FUNCTION__);
 		/*
 		 * Write access to directory required to delete files.
 		 */
@@ -576,7 +562,13 @@
 		 * and distance past previous entry (if there
 		 * is a previous entry in this block) in dp->i_count.
 		 * Save directory inode pointer in ndp->ni_dvp for dirremove().
+		 *
+		 * Technically we shouldn't be setting these in the
+		 * WANTPARENT case (first lookup in rename()), but any
+		 * lookups that will result in directory changes will
+		 * overwrite these.
 		 */
+		dp->i_offset = i_offset;
 		if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0)
 			dp->i_count = 0;
 		else
@@ -621,6 +613,7 @@
 		 * Careful about locking second inode.
 		 * This can only occur if the target is ".".
 		 */
+		dp->i_offset = i_offset;
 		if (dp->i_number == ino)
 			return (EISDIR);
 		if (dd_ino != NULL)
@@ -656,10 +649,7 @@
 	 */
 	pdp = vdp;
 	if (flags & ISDOTDOT) {
-		ltype = VOP_ISLOCKED(pdp);
-		VOP_UNLOCK(pdp, 0);	/* race to get the inode */
-		error = VFS_VGET(vdp->v_mount, ino, cnp->cn_lkflags, &tdp);
-		vn_lock(pdp, ltype | LK_RETRY);
+		error = vn_vget_ino(pdp, ino, cnp->cn_lkflags, &tdp);
 		if (pdp->v_iflag & VI_DOOMED) {
 			if (error == 0)
 				vput(tdp);
@@ -692,7 +682,7 @@
 		if (ltype != VOP_ISLOCKED(vdp)) {
 			if (ltype == LK_EXCLUSIVE)
 				vn_lock(vdp, LK_UPGRADE | LK_RETRY);
-			else /* if (ltype == LK_SHARED) */
+			else	/* if (ltype == LK_SHARED) */
 				vn_lock(vdp, LK_DOWNGRADE | LK_RETRY);
 		}
 		*vpp = vdp;
@@ -711,6 +701,102 @@
 	return (0);
 }
 
+int
+ext2_search_dirblock(struct inode *ip, void *data, int *foundp,
+    const char *name, int namelen, int *entryoffsetinblockp,
+    doff_t *offp, doff_t *prevoffp, doff_t *endusefulp,
+    struct ext2fs_searchslot *ssp)
+{
+	struct vnode *vdp;
+	struct ext2fs_direct_2 *ep, *top;
+	uint32_t bsize = ip->i_e2fs->e2fs_bsize;
+	int offset = *entryoffsetinblockp;
+	int namlen;
+
+	vdp = ITOV(ip);
+
+	ep = (struct ext2fs_direct_2 *)((char *)data + offset);
+	top = (struct ext2fs_direct_2 *)((char *)data +
+	    bsize - EXT2_DIR_REC_LEN(0));
+
+	while (ep < top) {
+		/*
+		 * Full validation checks are slow, so we only check
+		 * enough to insure forward progress through the
+		 * directory. Complete checks can be run by setting
+		 * "vfs.e2fs.dirchk" to be true.
+		 */
+		if (ep->e2d_reclen == 0 ||
+		    (dirchk && ext2_dirbadentry(vdp, ep, offset))) {
+			int i;
+
+			ext2_dirbad(ip, *offp, "mangled entry");
+			i = bsize - (offset & (bsize - 1));
+			*offp += i;
+			offset += i;
+			continue;
+		}
+
+		/*
+		 * If an appropriate sized slot has not yet been found,
+		 * check to see if one is available. Also accumulate space
+		 * in the current block so that we can determine if
+		 * compaction is viable.
+		 */
+		if (ssp->slotstatus != FOUND) {
+			int size = ep->e2d_reclen;
+
+			if (ep->e2d_ino != 0)
+				size -= EXT2_DIR_REC_LEN(ep->e2d_namlen);
+			if (size > 0) {
+				if (size >= ssp->slotneeded) {
+					ssp->slotstatus = FOUND;
+					ssp->slotoffset = *offp;
+					ssp->slotsize = ep->e2d_reclen;
+				} else if (ssp->slotstatus == NONE) {
+					ssp->slotfreespace += size;
+					if (ssp->slotoffset == -1)
+						ssp->slotoffset = *offp;
+					if (ssp->slotfreespace >= ssp->slotneeded) {
+						ssp->slotstatus = COMPACT;
+						ssp->slotsize = *offp +
+						    ep->e2d_reclen -
+						    ssp->slotoffset;
+					}
+				}
+			}
+		}
+		/*
+		 * Check for a name match.
+		 */
+		if (ep->e2d_ino) {
+			namlen = ep->e2d_namlen;
+			if (namlen == namelen &&
+			    !bcmp(name, ep->e2d_name, (unsigned)namlen)) {
+				/*
+				 * Save directory entry's inode number and
+				 * reclen in ndp->ni_ufs area, and release
+				 * directory buffer.
+				 */
+				*foundp = 1;
+				return (0);
+			}
+		}
+		*prevoffp = *offp;
+		*offp += ep->e2d_reclen;
+		offset += ep->e2d_reclen;
+		*entryoffsetinblockp = offset;
+		if (ep->e2d_ino)
+			*endusefulp = *offp;
+		/*
+		 * Get pointer to the next entry.
+		 */
+		ep = (struct ext2fs_direct_2 *)((char *)data + offset);
+	}
+
+	return (0);
+}
+
 void
 ext2_dirbad(struct inode *ip, doff_t offset, char *how)
 {
@@ -722,7 +808,7 @@
 			mp->mnt_stat.f_mntonname, (u_long)ip->i_number,(long)offset, how);
 	else
 	(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);
+	    mp->mnt_stat.f_mntonname, (u_long)ip->i_number, (long)offset, how);
 
 }
 
@@ -741,9 +827,9 @@
 ext2_dirbadentry(struct vnode *dp, struct ext2fs_direct_2 *de,
     int entryoffsetinblock)
 {
-	int	DIRBLKSIZ = VTOI(dp)->i_e2fs->e2fs_bsize;
+	int DIRBLKSIZ = VTOI(dp)->i_e2fs->e2fs_bsize;
 
-	char * error_msg = NULL;
+	char *error_msg = NULL;
 
 	if (de->e2d_reclen < EXT2_DIR_REC_LEN(1))
 		error_msg = "rec_len is smaller than minimal";
@@ -778,19 +864,15 @@
 int
 ext2_direnter(struct inode *ip, struct vnode *dvp, struct componentname *cnp)
 {
-	struct ext2fs_direct_2 *ep, *nep;
 	struct inode *dp;
-	struct buf *bp;
 	struct ext2fs_direct_2 newdir;
 	struct iovec aiov;
 	struct uio auio;
-	u_int dsize;
-	int error, loc, newentrysize, spacefree;
-	char *dirbuf;
-	int     DIRBLKSIZ = ip->i_e2fs->e2fs_bsize;
+	int error, newentrysize;
+	int DIRBLKSIZ = ip->i_e2fs->e2fs_bsize;
 
 
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 	if ((cnp->cn_flags & SAVENAME) == 0)
 		panic("ext2_direnter: missing name");
 #endif
@@ -804,6 +886,28 @@
 		newdir.e2d_type = EXT2_FT_UNKNOWN;
 	bcopy(cnp->cn_nameptr, newdir.e2d_name, (unsigned)cnp->cn_namelen + 1);
 	newentrysize = EXT2_DIR_REC_LEN(newdir.e2d_namlen);
+
+	if (ext2_htree_has_idx(dp)) {
+		error = ext2_htree_add_entry(dvp, &newdir, cnp);
+		if (error) {
+			dp->i_flag &= ~IN_E3INDEX;
+			dp->i_flag |= IN_CHANGE | IN_UPDATE;
+		}
+		return (error);
+	}
+
+	if (EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_DIRHASHINDEX) &&
+	    !ext2_htree_has_idx(dp)) {
+		if ((dp->i_size / DIRBLKSIZ) == 1 &&
+		    dp->i_offset == DIRBLKSIZ) {
+			/*
+			 * Making indexed directory when one block is not
+			 * enough to save all entries.
+			 */
+			return ext2_htree_create_index(dvp, cnp, &newdir);
+		}
+	}
+
 	if (dp->i_count == 0) {
 		/*
 		 * If dp->i_count is 0, then namei could find no
@@ -835,6 +939,29 @@
 		return (error);
 	}
 
+	error = ext2_add_entry(dvp, &newdir);
+	if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
+		error = ext2_truncate(dvp, (off_t)dp->i_endoff, IO_SYNC,
+		    cnp->cn_cred, cnp->cn_thread);
+	return (error);
+}
+
+/*
+ * Insert an entry into the directory block.
+ * Compact the contents.
+ */
+int
+ext2_add_entry(struct vnode *dvp, struct ext2fs_direct_2 *entry)
+{
+	struct ext2fs_direct_2 *ep, *nep;
+	struct inode *dp;
+	struct buf *bp;
+	u_int dsize;
+	int error, loc, newentrysize, spacefree;
+	char *dirbuf;
+
+	dp = VTOI(dvp);
+
 	/*
 	 * If dp->i_count is non-zero, then namei found space
 	 * for the new entry in the range dp->i_offset to
@@ -866,6 +993,7 @@
 	 * dp->i_offset + dp->i_count would yield the
 	 * space.
 	 */
+	newentrysize = EXT2_DIR_REC_LEN(entry->e2d_namlen);
 	ep = (struct ext2fs_direct_2 *)dirbuf;
 	dsize = EXT2_DIR_REC_LEN(ep->e2d_namlen);
 	spacefree = ep->e2d_reclen - dsize;
@@ -891,15 +1019,15 @@
 	if (ep->e2d_ino == 0) {
 		if (spacefree + dsize < newentrysize)
 			panic("ext2_direnter: compact1");
-		newdir.e2d_reclen = spacefree + dsize;
+		entry->e2d_reclen = spacefree + dsize;
 	} else {
 		if (spacefree < newentrysize)
 			panic("ext2_direnter: compact2");
-		newdir.e2d_reclen = spacefree;
+		entry->e2d_reclen = spacefree;
 		ep->e2d_reclen = dsize;
 		ep = (struct ext2fs_direct_2 *)((char *)ep + dsize);
 	}
-	bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize);
+	bcopy((caddr_t)entry, (caddr_t)ep, (u_int)newentrysize);
 	if (DOINGASYNC(dvp)) {
 		bdwrite(bp);
 		error = 0;
@@ -907,9 +1035,6 @@
 		error = bwrite(bp);
 	}
 	dp->i_flag |= IN_CHANGE | IN_UPDATE;
-	if (!error && dp->i_endoff && dp->i_endoff < dp->i_size)
-		error = ext2_truncate(dvp, (off_t)dp->i_endoff, IO_SYNC,
-		    cnp->cn_cred, cnp->cn_thread);
 	return (error);
 }
 
@@ -1078,9 +1203,9 @@
 			break;
 		}
 		error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
-			sizeof(struct dirtemplate), (off_t)0, UIO_SYSSPACE,
-			IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, NULL,
-			NULL);
+		    sizeof(struct dirtemplate), (off_t)0, UIO_SYSSPACE,
+		    IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, NULL,
+		    NULL);
 		if (error != 0)
 			break;
 		namlen = dirbuf.dotdot_type;	/* like ufs little-endian */

Modified: trunk/sys/fs/ext2fs/ext2_mount.h
===================================================================
--- trunk/sys/fs/ext2fs/ext2_mount.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2_mount.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1982, 1986, 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -27,11 +28,11 @@
  * SUCH DAMAGE.
  *
  *	@(#)ufsmount.h	8.6 (Berkeley) 3/30/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_mount.h 311232 2017-01-04 02:43:33Z pfg $
  */
 
 #ifndef _FS_EXT2FS_EXT2_MOUNT_H_
-#define _FS_EXT2FS_EXT2_MOUNT_H_
+#define	_FS_EXT2FS_EXT2_MOUNT_H_
 
 #ifdef _KERNEL
 
@@ -59,20 +60,20 @@
 	struct bufobj *um_bo;
 };
 
-#define EXT2_LOCK(aa)		mtx_lock(&(aa)->um_lock)
-#define EXT2_UNLOCK(aa)	mtx_unlock(&(aa)->um_lock)
-#define EXT2_MTX(aa)		(&(aa)->um_lock)
+#define	EXT2_LOCK(aa)		mtx_lock(&(aa)->um_lock)
+#define	EXT2_UNLOCK(aa)	mtx_unlock(&(aa)->um_lock)
+#define	EXT2_MTX(aa)		(&(aa)->um_lock)
 
 /* Convert mount ptr to ext2fsmount ptr. */
-#define VFSTOEXT2(mp)	((struct ext2mount *)((mp)->mnt_data))
+#define	VFSTOEXT2(mp)	((struct ext2mount *)((mp)->mnt_data))
 
 /*
  * Macros to access file system parameters in the ufsmount structure.
  * Used by ufs_bmap.
  */
-#define MNINDIR(ump)			((ump)->um_nindir)
+#define	MNINDIR(ump)			((ump)->um_nindir)
 #define	blkptrtodb(ump, b)		((b) << (ump)->um_bptrtodb)
 #define	is_sequential(ump, a, b)	((b) == (a) + ump->um_seqinc)
-#endif /* _KERNEL */
+#endif	/* _KERNEL */
 
 #endif	/* !_FS_EXT2FS_EXT2_MOUNT_H_ */

Modified: trunk/sys/fs/ext2fs/ext2_subr.c
===================================================================
--- trunk/sys/fs/ext2fs/ext2_subr.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2_subr.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  *  modified for Lites 1.1
  *
@@ -33,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)ffs_subr.c	8.2 (Berkeley) 9/21/93
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_subr.c 311232 2017-01-04 02:43:33Z pfg $
  */
 
 #include <sys/param.h>
@@ -50,10 +51,11 @@
 #include <fs/ext2fs/ext2_extern.h>
 #include <fs/ext2fs/ext2fs.h>
 #include <fs/ext2fs/fs.h>
+#include <fs/ext2fs/ext2_extents.h>
+#include <fs/ext2fs/ext2_mount.h>
+#include <fs/ext2fs/ext2_dinode.h>
 
 #ifdef KDB
-#include <fs/ext2fs/ext2_mount.h>
-
 void	ext2_checkoverlap(struct buf *, struct inode *);
 #endif
 
@@ -68,23 +70,65 @@
 	struct inode *ip;
 	struct m_ext2fs *fs;
 	struct buf *bp;
-	int32_t lbn;
+	e2fs_lbn_t lbn;
 	int bsize, error;
+	daddr_t newblk;
+	struct ext4_extent *ep;
+	struct ext4_extent_path path;
 
 	ip = VTOI(vp);
 	fs = ip->i_e2fs;
 	lbn = lblkno(fs, offset);
 	bsize = blksize(fs, ip, lbn);
+	*bpp = NULL;
 
-	*bpp = NULL;
-	if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) {
+	/*
+	 * IN_E4EXTENTS requires special treatment as we can otherwise fall
+	 * back to the normal path.
+	 */
+	if (!(ip->i_flag & IN_E4EXTENTS))
+		goto normal;
+
+	memset(&path, 0, sizeof(path));
+	if (ext4_ext_find_extent(fs, ip, lbn, &path) == NULL)
+		goto normal;
+	ep = path.ep_ext;
+	if (ep == NULL)
+		goto normal;
+
+	newblk = lbn - ep->e_blk +
+	    (ep->e_start_lo | (daddr_t)ep->e_start_hi << 32);
+
+	if (path.ep_bp != NULL) {
+		brelse(path.ep_bp);
+		path.ep_bp = NULL;
+	}
+	error = bread(ip->i_devvp, fsbtodb(fs, newblk), bsize, NOCRED, &bp);
+	if (error != 0) {
 		brelse(bp);
 		return (error);
 	}
 	if (res)
 		*res = (char *)bp->b_data + blkoff(fs, offset);
+	/*
+	 * If IN_E4EXTENTS is enabled we would get a wrong offset so
+	 * reset b_offset here.
+	 */
+	bp->b_offset = lbn * bsize;
 	*bpp = bp;
 	return (0);
+
+normal:
+	if (*bpp == NULL) {
+		if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) {
+			brelse(bp);
+			return (error);
+		}
+		if (res)
+			*res = (char *)bp->b_data + blkoff(fs, offset);
+		*bpp = bp;
+	}
+	return (0);
 }
 
 #ifdef KDB
@@ -92,7 +136,7 @@
 ext2_checkoverlap(struct buf *bp, struct inode *ip)
 {
 	struct buf *ebp, *ep;
-	int32_t start, last;
+	e4fs_daddr_t start, last;
 	struct vnode *vp;
 
 	ebp = &buf[nbuf];
@@ -107,10 +151,10 @@
 		    ep->b_blkno + btodb(ep->b_bcount) <= start)
 			continue;
 		vprint("Disk overlap", vp);
-		(void)printf("\tstart %d, end %d overlap start %lld, end %ld\n",
-			start, last, (long long)ep->b_blkno,
-			(long)(ep->b_blkno + btodb(ep->b_bcount) - 1));
-		panic("Disk buffer overlap");
+		printf("\tstart %jd, end %jd overlap start %jd, end %jd\n",
+		    (intmax_t)start, (intmax_t)last, (intmax_t)ep->b_blkno,
+		    (intmax_t)(ep->b_blkno + btodb(ep->b_bcount) - 1));
+		panic("ext2_checkoverlap: Disk buffer overlap");
 	}
 }
 #endif /* KDB */
@@ -130,6 +174,7 @@
 	/* Initialize the cluster summary array. */
 	if (fs->e2fs_clustersum[cg].cs_init == 0) {
 		int run = 0;
+
 		bit = 1;
 		loc = 0;
 

Modified: trunk/sys/fs/ext2fs/ext2_vfsops.c
===================================================================
--- trunk/sys/fs/ext2fs/ext2_vfsops.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2_vfsops.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  *  modified for EXT2FS support in Lites 1.1
  *
@@ -33,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)ffs_vfsops.c	8.8 (Berkeley) 4/18/94
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_vfsops.c 311232 2017-01-04 02:43:33Z pfg $
  */
 
 #include <sys/param.h>
@@ -112,7 +113,7 @@
 	struct vfsoptlist *opts;
 	struct vnode *devvp;
 	struct thread *td;
-	struct ext2mount *ump = 0;
+	struct ext2mount *ump = NULL;
 	struct m_ext2fs *fs;
 	struct nameidata nd, *ndp = &nd;
 	accmode_t accmode;
@@ -141,7 +142,7 @@
 	 */
 	if (mp->mnt_flag & MNT_UPDATE) {
 		ump = VFSTOEXT2(mp);
-		fs = ump->um_e2fs; 
+		fs = ump->um_e2fs;
 		error = 0;
 		if (fs->e2fs_ronly == 0 &&
 		    vfs_flagopt(opts, "ro", NULL, 0)) {
@@ -152,7 +153,7 @@
 			if (mp->mnt_flag & MNT_FORCE)
 				flags |= FORCECLOSE;
 			error = ext2_flushfiles(mp, flags, td);
-			if ( error == 0 && fs->e2fs_wasvalid && ext2_cgupdate(ump, MNT_WAIT) == 0) {
+			if (error == 0 && fs->e2fs_wasvalid && ext2_cgupdate(ump, MNT_WAIT) == 0) {
 				fs->e2fs->e2fs_state |= E2FS_ISCLEAN;
 				ext2_sbupdate(ump, MNT_WAIT);
 			}
@@ -290,7 +291,8 @@
 		return (1);
 	}
 	if (es->e2fs_rev > E2FS_REV0) {
-		if (es->e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP) {
+		if (es->e2fs_features_incompat & ~(EXT2F_INCOMPAT_SUPP |
+						   EXT4F_RO_INCOMPAT_SUPP)) {
 			printf(
 "WARNING: mount of %s denied due to unsupported optional features\n",
 			    devtoname(dev));
@@ -307,8 +309,8 @@
 }
 
 /*
- * This computes the fields of the  ext2_sb_info structure from the
- * data in the ext2_super_block structure read in.
+ * This computes the fields of the m_ext2fs structure from the
+ * data in the ext2fs structure read in.
  */
 static int
 compute_sb_data(struct vnode *devvp, struct ext2fs *es,
@@ -331,7 +333,7 @@
 	fs->e2fs_fpg = es->e2fs_fpg;
 	fs->e2fs_ipg = es->e2fs_ipg;
 	if (es->e2fs_rev == E2FS_REV0) {
-		fs->e2fs_isize = E2FS_REV0_INODE_SIZE ;
+		fs->e2fs_isize = E2FS_REV0_INODE_SIZE;
 	} else {
 		fs->e2fs_isize = es->e2fs_inode_size;
 
@@ -354,17 +356,17 @@
 	}
 
 	fs->e2fs_ipb = fs->e2fs_bsize / EXT2_INODE_SIZE(fs);
-	fs->e2fs_itpg = fs->e2fs_ipg /fs->e2fs_ipb;
+	fs->e2fs_itpg = fs->e2fs_ipg / fs->e2fs_ipb;
 	/* s_resuid / s_resgid ? */
-	fs->e2fs_gcount = (es->e2fs_bcount - es->e2fs_first_dblock +
-	    EXT2_BLOCKS_PER_GROUP(fs) - 1) / EXT2_BLOCKS_PER_GROUP(fs);
+	fs->e2fs_gcount = howmany(es->e2fs_bcount - es->e2fs_first_dblock,
+	    EXT2_BLOCKS_PER_GROUP(fs));
 	e2fs_descpb = fs->e2fs_bsize / sizeof(struct ext2_gd);
-	db_count = (fs->e2fs_gcount + e2fs_descpb - 1) / e2fs_descpb;
+	db_count = howmany(fs->e2fs_gcount, e2fs_descpb);
 	fs->e2fs_gdbcount = db_count;
 	fs->e2fs_gd = malloc(db_count * fs->e2fs_bsize,
 	    M_EXT2MNT, M_WAITOK);
 	fs->e2fs_contigdirs = malloc(fs->e2fs_gcount *
-	    sizeof(*fs->e2fs_contigdirs), M_EXT2MNT, M_WAITOK);
+	    sizeof(*fs->e2fs_contigdirs), M_EXT2MNT, M_WAITOK | M_ZERO);
 
 	/*
 	 * Adjust logic_sb_block.
@@ -371,13 +373,14 @@
 	 * Godmar thinks: if the blocksize is greater than 1024, then
 	 * the superblock is logically part of block zero.
 	 */
-	if(fs->e2fs_bsize > SBSIZE)
+	if (fs->e2fs_bsize > SBSIZE)
 		logic_sb_block = 0;
 	for (i = 0; i < db_count; i++) {
-		error = bread(devvp ,
-			 fsbtodb(fs, logic_sb_block + i + 1 ),
-			fs->e2fs_bsize, NOCRED, &bp);
+		error = bread(devvp,
+		    fsbtodb(fs, logic_sb_block + i + 1),
+		    fs->e2fs_bsize, NOCRED, &bp);
 		if (error) {
+			free(fs->e2fs_contigdirs, M_EXT2MNT);
 			free(fs->e2fs_gd, M_EXT2MNT);
 			brelse(bp);
 			return (error);
@@ -384,21 +387,35 @@
 		}
 		e2fs_cgload((struct ext2_gd *)bp->b_data,
 		    &fs->e2fs_gd[
-			i * fs->e2fs_bsize / sizeof(struct ext2_gd)],
+		    i * fs->e2fs_bsize / sizeof(struct ext2_gd)],
 		    fs->e2fs_bsize);
 		brelse(bp);
 		bp = NULL;
 	}
+	/* Initialization for the ext2 Orlov allocator variant. */
 	fs->e2fs_total_dir = 0;
-	for (i=0; i < fs->e2fs_gcount; i++){
+	for (i = 0; i < fs->e2fs_gcount; i++)
 		fs->e2fs_total_dir += fs->e2fs_gd[i].ext2bgd_ndirs;
-		fs->e2fs_contigdirs[i] = 0;
-	}
+
 	if (es->e2fs_rev == E2FS_REV0 ||
 	    !EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_LARGEFILE))
 		fs->e2fs_maxfilesize = 0x7fffffff;
-	else
-		fs->e2fs_maxfilesize = 0x7fffffffffffffff;
+	else {
+		fs->e2fs_maxfilesize = 0xffffffffffff;
+		if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_HUGE_FILE))
+			fs->e2fs_maxfilesize = 0x7fffffffffffffff;
+	}
+	if (es->e4fs_flags & E2FS_UNSIGNED_HASH) {
+		fs->e2fs_uhash = 3;
+	} else if ((es->e4fs_flags & E2FS_SIGNED_HASH) == 0) {
+#ifdef __CHAR_UNSIGNED__
+		es->e4fs_flags |= E2FS_UNSIGNED_HASH;
+		fs->e2fs_uhash = 3;
+#else
+		es->e4fs_flags |= E2FS_SIGNED_HASH;
+#endif
+	}
+
 	return (0);
 }
 
@@ -453,7 +470,7 @@
 	fs = VFSTOEXT2(mp)->um_e2fs;
 	bcopy(bp->b_data, fs->e2fs, sizeof(struct ext2fs));
 
-	if((error = compute_sb_data(devvp, es, fs)) != 0) {
+	if ((error = compute_sb_data(devvp, es, fs)) != 0) {
 		brelse(bp);
 		return (error);
 	}
@@ -500,7 +517,7 @@
 			MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp);
 			return (error);
 		}
-		ext2_ei2i((struct ext2fs_dinode *) ((char *)bp->b_data +
+		ext2_ei2i((struct ext2fs_dinode *)((char *)bp->b_data +
 		    EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)), ip);
 		brelse(bp);
 		VOP_UNLOCK(vp, 0);
@@ -525,7 +542,8 @@
 	struct csum *sump;
 	int error;
 	int ronly;
-	int i, size;
+	int i;
+	u_long size;
 	int32_t *lp;
 	int32_t e2fs_maxcontig;
 
@@ -584,13 +602,13 @@
 
 	/*
 	 * I don't know whether this is the right strategy. Note that
-	 * we dynamically allocate both an ext2_sb_info and an ext2_super_block
+	 * we dynamically allocate both an m_ext2fs and an ext2fs
 	 * while Linux keeps the super block in a locked buffer.
 	 */
 	ump->um_e2fs = malloc(sizeof(struct m_ext2fs),
-		M_EXT2MNT, M_WAITOK);
+	    M_EXT2MNT, M_WAITOK | M_ZERO);
 	ump->um_e2fs->e2fs = malloc(sizeof(struct ext2fs),
-		M_EXT2MNT, M_WAITOK);
+	    M_EXT2MNT, M_WAITOK);
 	mtx_init(EXT2_MTX(ump), "EXT2FS", "EXT2FS Lock", MTX_DEF);
 	bcopy(es, ump->um_e2fs->e2fs, (u_int)sizeof(struct ext2fs));
 	if ((error = compute_sb_data(devvp, ump->um_e2fs->e2fs, ump->um_e2fs)))
@@ -598,8 +616,8 @@
 
 	/*
 	 * Calculate the maximum contiguous blocks and size of cluster summary
-	 * array.  In FFS this is done by newfs; however, the superblock 
-	 * in ext2fs doesn't have these variables, so we can calculate 
+	 * array.  In FFS this is done by newfs; however, the superblock
+	 * in ext2fs doesn't have these variables, so we can calculate
 	 * them here.
 	 */
 	e2fs_maxcontig = MAX(1, MAXPHYS / ump->um_e2fs->e2fs_bsize);
@@ -630,7 +648,7 @@
 	 */
 	fs->e2fs_wasvalid = fs->e2fs->e2fs_state & E2FS_ISCLEAN ? 1 : 0;
 	if (ronly == 0) {
-		fs->e2fs_fmod = 1;		/* mark it modified */
+		fs->e2fs_fmod = 1;	/* mark it modified */
 		fs->e2fs->e2fs_state &= ~E2FS_ISCLEAN;	/* set fs invalid */
 	}
 	mp->mnt_data = ump;
@@ -659,8 +677,8 @@
 	 * Initialize filesystem stat information in mount struct.
 	 */
 	MNT_ILOCK(mp);
- 	mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED |
-            MNTK_EXTENDED_SHARED;
+	mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED |
+	    MNTK_USES_BCACHE;
 	MNT_IUNLOCK(mp);
 	return (0);
 out:
@@ -674,7 +692,7 @@
 		PICKUP_GIANT();
 	}
 	if (ump) {
-	  	mtx_destroy(EXT2_MTX(ump));
+		mtx_destroy(EXT2_MTX(ump));
 		free(ump->um_e2fs->e2fs_gd, M_EXT2MNT);
 		free(ump->um_e2fs->e2fs_contigdirs, M_EXT2MNT);
 		free(ump->um_e2fs->e2fs, M_EXT2MNT);
@@ -709,8 +727,8 @@
 	ronly = fs->e2fs_ronly;
 	if (ronly == 0 && ext2_cgupdate(ump, MNT_WAIT) == 0) {
 		if (fs->e2fs_wasvalid)
- 			fs->e2fs->e2fs_state |= E2FS_ISCLEAN;
- 		ext2_sbupdate(ump, MNT_WAIT);
+			fs->e2fs->e2fs_state |= E2FS_ISCLEAN;
+		ext2_sbupdate(ump, MNT_WAIT);
 	}
 
 	DROP_GIANT();
@@ -747,8 +765,9 @@
 	error = vflush(mp, 0, flags, td);
 	return (error);
 }
+
 /*
- * Get file system statistics.
+ * Get filesystem statistics.
  */
 int
 ext2_statfs(struct mount *mp, struct statfs *sbp)
@@ -853,7 +872,7 @@
 	}
 
 	/*
-	 * Force stale file system control information to be flushed.
+	 * Force stale filesystem control information to be flushed.
 	 */
 	if (waitfor != MNT_LAZY) {
 		vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
@@ -888,7 +907,6 @@
 	struct ext2mount *ump;
 	struct buf *bp;
 	struct vnode *vp;
-	struct cdev *dev;
 	struct thread *td;
 	int i, error;
 	int used_blocks;
@@ -899,15 +917,6 @@
 		return (error);
 
 	ump = VFSTOEXT2(mp);
-	dev = ump->um_dev;
-
-	/*
-	 * If this malloc() is performed after the getnewvnode()
-	 * it might block, leaving a vnode with a NULL v_data to be
-	 * found by ext2_sync() if a sync happens to fire right then,
-	 * which will cause a panic because ext2_sync() blindly
-	 * dereferences vp->v_data (as well it should).
-	 */
 	ip = malloc(sizeof(struct inode), M_EXT2NODE, M_WAITOK | M_ZERO);
 
 	/* Allocate a new vnode/inode. */
@@ -919,7 +928,7 @@
 	vp->v_data = ip;
 	ip->i_vnode = vp;
 	ip->i_e2fs = fs = ump->um_e2fs;
-	ip->i_ump  = ump;
+	ip->i_ump = ump;
 	ip->i_number = ino;
 
 	lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
@@ -948,8 +957,8 @@
 		return (error);
 	}
 	/* convert ext2 inode to dinode */
-	ext2_ei2i((struct ext2fs_dinode *) ((char *)bp->b_data + EXT2_INODE_SIZE(fs) *
-			ino_to_fsbo(fs, ino)), ip);
+	ext2_ei2i((struct ext2fs_dinode *)((char *)bp->b_data + EXT2_INODE_SIZE(fs) *
+	    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;
@@ -958,15 +967,19 @@
 	 * Now we want to make sure that block pointers for unused
 	 * blocks are zeroed out - ext2_balloc depends on this
 	 * although for regular files and directories only
+	 *
+	 * If IN_E4EXTENTS is enabled, unused blocks are not zeroed
+	 * out because we could corrupt the extent tree.
 	 */
-	if(S_ISDIR(ip->i_mode) || S_ISREG(ip->i_mode)) {
-		used_blocks = (ip->i_size+fs->e2fs_bsize-1) / fs->e2fs_bsize;
+	if (!(ip->i_flag & IN_E4EXTENTS) &&
+	    (S_ISDIR(ip->i_mode) || S_ISREG(ip->i_mode))) {
+		used_blocks = howmany(ip->i_size, fs->e2fs_bsize);
 		for (i = used_blocks; i < EXT2_NDIR_BLOCKS; i++)
 			ip->i_db[i] = 0;
 	}
-/*
+#ifdef EXT2FS_DEBUG
 	ext2_print_inode(ip);
-*/
+#endif
 	bqrelse(bp);
 
 	/*
@@ -988,7 +1001,7 @@
 	 * already have one. This should only happen on old filesystems.
 	 */
 	if (ip->i_gen == 0) {
-		ip->i_gen = random() / 2 + 1;
+		ip->i_gen = random() + 1;
 		if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
 			ip->i_flag |= IN_MODIFIED;
 	}
@@ -1088,6 +1101,7 @@
 		allerror = error;
 	return (allerror);
 }
+
 /*
  * Return the root of a filesystem.
  */

Modified: trunk/sys/fs/ext2fs/ext2_vnops.c
===================================================================
--- trunk/sys/fs/ext2fs/ext2_vnops.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2_vnops.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  *  modified for EXT2FS support in Lites 1.1
  *
@@ -39,7 +40,7 @@
  *
  *	@(#)ufs_vnops.c	8.7 (Berkeley) 2/3/94
  *	@(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2_vnops.c 311232 2017-01-04 02:43:33Z pfg $
  */
 
 #include "opt_suiddir.h"
@@ -48,11 +49,13 @@
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/fcntl.h>
+#include <sys/filio.h>
 #include <sys/stat.h>
 #include <sys/bio.h>
 #include <sys/buf.h>
 #include <sys/endian.h>
 #include <sys/priv.h>
+#include <sys/rwlock.h>
 #include <sys/mount.h>
 #include <sys/unistd.h>
 #include <sys/time.h>
@@ -64,15 +67,15 @@
 #include <sys/file.h>
 
 #include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_object.h>
 #include <vm/vm_page.h>
-#include <vm/vm_object.h>
-#include <vm/vm_extern.h>
+#include <vm/vm_pager.h>
 #include <vm/vnode_pager.h>
 
 #include "opt_directio.h"
 
-#include <fs/fifofs/fifo.h>
-
 #include <ufs/ufs/dir.h>
 
 #include <fs/ext2fs/fs.h>
@@ -85,6 +88,8 @@
 
 static int ext2_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *);
 static void ext2_itimes_locked(struct vnode *);
+static int ext4_ext_read(struct vop_read_args *);
+static int ext2_ind_read(struct vop_read_args *);
 
 static vop_access_t	ext2_access;
 static int ext2_chmod(struct vnode *, int, struct ucred *, struct thread *);
@@ -93,7 +98,9 @@
 static vop_close_t	ext2_close;
 static vop_create_t	ext2_create;
 static vop_fsync_t	ext2_fsync;
+static vop_getpages_t	ext2_getpages;
 static vop_getattr_t	ext2_getattr;
+static vop_ioctl_t	ext2_ioctl;
 static vop_link_t	ext2_link;
 static vop_mkdir_t	ext2_mkdir;
 static vop_mknod_t	ext2_mknod;
@@ -122,8 +129,10 @@
 	.vop_close =		ext2_close,
 	.vop_create =		ext2_create,
 	.vop_fsync =		ext2_fsync,
+	.vop_getpages =		ext2_getpages,
 	.vop_getattr =		ext2_getattr,
 	.vop_inactive =		ext2_inactive,
+	.vop_ioctl =		ext2_ioctl,
 	.vop_link =		ext2_link,
 	.vop_lookup =		vfs_cache_lookup,
 	.vop_mkdir =		ext2_mkdir,
@@ -184,7 +193,7 @@
 	struct inode *ip;
 	struct timespec ts;
 
-	ASSERT_VI_LOCKED(vp, __func__);	
+	ASSERT_VI_LOCKED(vp, __func__);
 
 	ip = VTOI(vp);
 	if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0)
@@ -232,8 +241,10 @@
 	error =
 	    ext2_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
 	    ap->a_dvp, ap->a_vpp, ap->a_cnp);
-	if (error)
+	if (error != 0)
 		return (error);
+	if ((ap->a_cnp->cn_flags & MAKEENTRY) != 0)
+		cache_enter(ap->a_dvp, *ap->a_vpp, ap->a_cnp);
 	return (0);
 }
 
@@ -373,7 +384,7 @@
 	}
 	if (vap->va_flags != VNOVAL) {
 		/* Disallow flags not supported by ext2fs. */
-		if(vap->va_flags & ~(SF_APPEND | SF_IMMUTABLE | UF_NODUMP))
+		if (vap->va_flags & ~(SF_APPEND | SF_IMMUTABLE | UF_NODUMP))
 			return (EOPNOTSUPP);
 
 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
@@ -392,21 +403,17 @@
 		 * if securelevel > 0 and any existing system flags are set.
 		 */
 		if (!priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0)) {
-			if (ip->i_flags &
-			    (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) {
+			if (ip->i_flags & (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)
+			if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND) ||
+			    ((vap->va_flags ^ ip->i_flags) & SF_SETTABLE))
 				return (EPERM);
-			ip->i_flags &= SF_SETTABLE;
-			ip->i_flags |= (vap->va_flags & UF_SETTABLE);
 		}
+		ip->i_flags = vap->va_flags;
 		ip->i_flag |= IN_CHANGE;
 		if (ip->i_flags & (IMMUTABLE | APPEND))
 			return (0);
@@ -458,16 +465,14 @@
 		    ((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);
+		ip->i_flag |= IN_CHANGE | IN_MODIFIED;
 		if (vap->va_atime.tv_sec != VNOVAL) {
+			ip->i_flag &= ~IN_ACCESS;
 			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_flag &= ~IN_UPDATE;
 			ip->i_mtime = vap->va_mtime.tv_sec;
 			ip->i_mtimensec = vap->va_mtime.tv_nsec;
 		}
@@ -663,14 +668,10 @@
 	struct inode *ip;
 	int error;
 
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 	if ((cnp->cn_flags & HASBUF) == 0)
 		panic("ext2_link: no name");
 #endif
-	if (tdvp->v_mount != vp->v_mount) {
-		error = EXDEV;
-		goto out;
-	}
 	ip = VTOI(vp);
 	if ((nlink_t)ip->i_nlink >= EXT2_LINK_MAX) {
 		error = EMLINK;
@@ -732,7 +733,7 @@
 	int error = 0;
 	u_char namlen;
 
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 	if ((tcnp->cn_flags & HASBUF) == 0 ||
 	    (fcnp->cn_flags & HASBUF) == 0)
 		panic("ext2_rename: no name");
@@ -776,10 +777,10 @@
 	dp = VTOI(fdvp);
 	ip = VTOI(fvp);
 	if (ip->i_nlink >= EXT2_LINK_MAX) {
- 		VOP_UNLOCK(fvp, 0);
- 		error = EMLINK;
- 		goto abortit;
- 	}
+		VOP_UNLOCK(fvp, 0);
+		error = EMLINK;
+		goto abortit;
+	}
 	if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))
 	    || (dp->i_flags & APPEND)) {
 		VOP_UNLOCK(fvp, 0);
@@ -895,7 +896,7 @@
 		vput(tdvp);
 	} else {
 		if (xp->i_devvp != dp->i_devvp || xp->i_devvp != ip->i_devvp)
-		       panic("ext2_rename: EXDEV");
+			panic("ext2_rename: EXDEV");
 		/*
 		 * Short circuit rename(foo, foo).
 		 */
@@ -918,8 +919,8 @@
 		 * to it. Also, ensure source and target are compatible
 		 * (both directories, or both not directories).
 		 */
-		if ((xp->i_mode&IFMT) == IFDIR) {
-			if (! ext2_dirempty(xp, dp->i_number, tcnp->cn_cred) || 
+		if ((xp->i_mode & IFMT) == IFDIR) {
+			if (!ext2_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
 			    xp->i_nlink > 2) {
 				error = ENOTEMPTY;
 				goto bad;
@@ -943,8 +944,8 @@
 		 * of the target directory.
 		 */
 		if (doingdirectory && !newparent) {
-		       dp->i_nlink--;
-		       dp->i_flag |= IN_CHANGE;
+			dp->i_nlink--;
+			dp->i_flag |= IN_CHANGE;
 		}
 		vput(tdvp);
 		/*
@@ -983,10 +984,10 @@
 		dp = VTOI(fdvp);
 	} else {
 		/*
-		 * From name has disappeared.
+		 * From name has disappeared.  IN_RENAME is not sufficient
+		 * to protect against directory races due to timing windows,
+		 * so we can't panic here.
 		 */
-		if (doingdirectory)
-			panic("ext2_rename: lost dir entry");
 		vrele(ap->a_fvp);
 		return (0);
 	}
@@ -1001,8 +1002,11 @@
 	 * rename.
 	 */
 	if (xp != ip) {
-		if (doingdirectory)
-			panic("ext2_rename: lost dir entry");
+		/*
+		 * From name resolves to a different inode.  IN_RENAME is
+		 * not sufficient protection against timing window races
+		 * so we can't panic here.
+		 */
 	} else {
 		/*
 		 * If the source is a directory with a
@@ -1014,9 +1018,9 @@
 			dp->i_nlink--;
 			dp->i_flag |= IN_CHANGE;
 			error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
-				sizeof(struct dirtemplate), (off_t)0,
-				UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK,
-				tcnp->cn_cred, NOCRED, NULL, NULL);
+			    sizeof(struct dirtemplate), (off_t)0,
+			    UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK,
+			    tcnp->cn_cred, NOCRED, NULL, NULL);
 			if (error == 0) {
 				/* Like ufs little-endian: */
 				namlen = dirbuf.dotdot_type;
@@ -1027,7 +1031,7 @@
 					    "rename: mangled dir");
 				} else {
 					dirbuf.dotdot_ino = newparent;
-					(void) vn_rdwr(UIO_WRITE, fvp,
+					(void)vn_rdwr(UIO_WRITE, fvp,
 					    (caddr_t)&dirbuf,
 					    sizeof(struct dirtemplate),
 					    (off_t)0, UIO_SYSSPACE,
@@ -1083,7 +1087,7 @@
 	struct dirtemplate dirtemplate, *dtp;
 	int error, dmode;
 
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 	if ((cnp->cn_flags & HASBUF) == 0)
 		panic("ext2_mkdir: no name");
 #endif
@@ -1110,12 +1114,12 @@
 		 * if we are hacking owners here, (only do this where told to)
 		 * and we are not giving it TOO root, (would subvert quotas)
 		 * then go ahead and give it to the other user.
-		 * The new directory also inherits the SUID bit. 
+		 * The new directory also inherits the SUID bit.
 		 * If user's UID and dir UID are the same,
 		 * 'give it away' so that the SUID is still forced on.
 		 */
-		if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
-		   (dp->i_mode & ISUID) && dp->i_uid) {
+		if ((dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
+		    (dp->i_mode & ISUID) && dp->i_uid) {
 			dmode |= ISUID;
 			ip->i_uid = dp->i_uid;
 		} else {
@@ -1154,10 +1158,11 @@
 	dirtemplate = *dtp;
 	dirtemplate.dot_ino = ip->i_number;
 	dirtemplate.dotdot_ino = dp->i_number;
-	/* note that in ext2 DIRBLKSIZ == blocksize, not DEV_BSIZE 
-	 * so let's just redefine it - for this function only
+	/*
+	 * note that in ext2 DIRBLKSIZ == blocksize, not DEV_BSIZE so let's
+	 * just redefine it - for this function only
 	 */
-#undef  DIRBLKSIZ 
+#undef  DIRBLKSIZ
 #define DIRBLKSIZ  VTOI(dvp)->i_e2fs->e2fs_bsize
 	dirtemplate.dotdot_reclen = DIRBLKSIZ - 12;
 	error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
@@ -1222,7 +1227,6 @@
 	 *  the current directory and thus be
 	 *  non-empty.)
 	 */
-	error = 0;
 	if (ip->i_nlink != 2 || !ext2_dirempty(ip, dp->i_number, cnp->cn_cred)) {
 		error = ENOTEMPTY;
 		goto out;
@@ -1328,12 +1332,10 @@
 {
 	struct buf *bp = ap->a_bp;
 	struct vnode *vp = ap->a_vp;
-	struct inode *ip;
 	struct bufobj *bo;
-	int32_t blkno;
+	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) {
@@ -1394,7 +1396,7 @@
 /*
  * Kqfilter wrapper for fifos.
  *
- * Fall through to ext2 kqfilter routines if needed 
+ * Fall through to ext2 kqfilter routines if needed
  */
 static int
 ext2fifo_kqfilter(struct vop_kqfilter_args *ap)
@@ -1413,30 +1415,68 @@
 static int
 ext2_pathconf(struct vop_pathconf_args *ap)
 {
+	int error = 0;
 
 	switch (ap->a_name) {
 	case _PC_LINK_MAX:
 		*ap->a_retval = EXT2_LINK_MAX;
-		return (0);
+		break;
 	case _PC_NAME_MAX:
 		*ap->a_retval = NAME_MAX;
-		return (0);
+		break;
 	case _PC_PATH_MAX:
 		*ap->a_retval = PATH_MAX;
-		return (0);
+		break;
 	case _PC_PIPE_BUF:
 		*ap->a_retval = PIPE_BUF;
-		return (0);
+		break;
 	case _PC_CHOWN_RESTRICTED:
 		*ap->a_retval = 1;
-		return (0);
+		break;
 	case _PC_NO_TRUNC:
 		*ap->a_retval = 1;
-		return (0);
+		break;
+	case _PC_MIN_HOLE_SIZE:
+		*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
+		break;
+	case _PC_ASYNC_IO:
+		/* _PC_ASYNC_IO should have been handled by upper layers. */
+		KASSERT(0, ("_PC_ASYNC_IO should not get here"));
+		error = EINVAL;
+		break;
+	case _PC_PRIO_IO:
+		*ap->a_retval = 0;
+		break;
+	case _PC_SYNC_IO:
+		*ap->a_retval = 0;
+		break;
+	case _PC_ALLOC_SIZE_MIN:
+		*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize;
+		break;
+	case _PC_FILESIZEBITS:
+		*ap->a_retval = 64;
+		break;
+	case _PC_REC_INCR_XFER_SIZE:
+		*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
+		break;
+	case _PC_REC_MAX_XFER_SIZE:
+		*ap->a_retval = -1;	/* means ``unlimited'' */
+		break;
+	case _PC_REC_MIN_XFER_SIZE:
+		*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
+		break;
+	case _PC_REC_XFER_ALIGN:
+		*ap->a_retval = PAGE_SIZE;
+		break;
+	case _PC_SYMLINK_MAX:
+		*ap->a_retval = MAXPATHLEN;
+		break;
+
 	default:
-		return (EINVAL);
+		error = EINVAL;
+		break;
 	}
-	/* NOTREACHED */
+	return (error);
 }
 
 /*
@@ -1492,7 +1532,7 @@
 	int error;
 
 	pdir = VTOI(dvp);
-#ifdef DIAGNOSTIC
+#ifdef INVARIANTS
 	if ((cnp->cn_flags & HASBUF) == 0)
 		panic("ext2_makeinode: no name");
 #endif
@@ -1516,9 +1556,9 @@
 		 * then go ahead and give it to the other user.
 		 * Note that this drops off the execute bits for security.
 		 */
-		if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
-		     (pdir->i_mode & ISUID) &&
-		     (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) {
+		if ((dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
+		    (pdir->i_mode & ISUID) &&
+		    (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) {
 			ip->i_uid = pdir->i_uid;
 			mode &= ~07111;
 		} else {
@@ -1572,6 +1612,28 @@
 {
 	struct vnode *vp;
 	struct inode *ip;
+	int error;
+
+	vp = ap->a_vp;
+	ip = VTOI(vp);
+
+	/* EXT4_EXT_LOCK(ip); */
+	if (ip->i_flag & IN_E4EXTENTS)
+		error = ext4_ext_read(ap);
+	else
+		error = ext2_ind_read(ap);
+	/* EXT4_EXT_UNLOCK(ip); */
+	return (error);
+}
+
+/*
+ * Vnode op for reading.
+ */
+static int
+ext2_ind_read(struct vop_read_args *ap)
+{
+	struct vnode *vp;
+	struct inode *ip;
 	struct uio *uio;
 	struct m_ext2fs *fs;
 	struct buf *bp;
@@ -1606,7 +1668,7 @@
 	fs = ip->i_e2fs;
 	if (uio->uio_offset < ip->i_size &&
 	    uio->uio_offset >= fs->e2fs_maxfilesize)
-	    	return (EOVERFLOW);
+		return (EOVERFLOW);
 
 	for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
 		if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
@@ -1624,11 +1686,13 @@
 
 		if (lblktosize(fs, nextlbn) >= ip->i_size)
 			error = bread(vp, lbn, size, NOCRED, &bp);
-		else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0)
+		else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
 			error = cluster_read(vp, ip->i_size, lbn, size,
-			    NOCRED, blkoffset + uio->uio_resid, seqcount, &bp);
-		else if (seqcount > 1) {
-			int nextsize = blksize(fs, ip, nextlbn);
+			    NOCRED, blkoffset + uio->uio_resid, seqcount,
+			    0, &bp);
+		} else if (seqcount > 1) {
+			u_int nextsize = blksize(fs, ip, nextlbn);
+
 			error = breadn(vp, lbn,
 			    size, &nextlbn, &nextsize, 1, NOCRED, &bp);
 		} else
@@ -1662,7 +1726,7 @@
 			xfersize = size;
 		}
 		error = uiomove((char *)bp->b_data + blkoffset,
-  			(int)xfersize, uio);
+		    (int)xfersize, uio);
 		if (error)
 			break;
 
@@ -1686,11 +1750,11 @@
 		}
 	}
 
-	/* 
-	 * This can only happen in the case of an error
-	 * because the loop above resets bp to NULL on each iteration
-	 * and on normal completion has not set a new value into it.
-	 * so it must have come from a 'break' statement
+	/*
+	 * This can only happen in the case of an error because the loop
+	 * above resets bp to NULL on each iteration and on normal
+	 * completion has not set a new value into it. so it must have come
+	 * from a 'break' statement
 	 */
 	if (bp != NULL) {
 		if (ioflag & (IO_VMIO|IO_DIRECT)) {
@@ -1702,12 +1766,127 @@
 	}
 
 	if ((error == 0 || uio->uio_resid != orig_resid) &&
-	    (vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
+	    (vp->v_mount->mnt_flag & (MNT_NOATIME | MNT_RDONLY)) == 0)
 		ip->i_flag |= IN_ACCESS;
 	return (error);
 }
 
+static int
+ext2_ioctl(struct vop_ioctl_args *ap)
+{
+
+	switch (ap->a_command) {
+	case FIOSEEKDATA:
+	case FIOSEEKHOLE:
+		return (vn_bmap_seekhole(ap->a_vp, ap->a_command,
+		    (off_t *)ap->a_data, ap->a_cred));
+	default:
+		return (ENOTTY);
+	}
+}
+
 /*
+ * this function handles ext4 extents block mapping
+ */
+static int
+ext4_ext_read(struct vop_read_args *ap)
+{
+	struct vnode *vp;
+	struct inode *ip;
+	struct uio *uio;
+	struct m_ext2fs *fs;
+	struct buf *bp;
+	struct ext4_extent nex, *ep;
+	struct ext4_extent_path path;
+	daddr_t lbn, newblk;
+	off_t bytesinfile;
+	int cache_type;
+	ssize_t orig_resid;
+	int error;
+	long size, xfersize, blkoffset;
+
+	vp = ap->a_vp;
+	ip = VTOI(vp);
+	uio = ap->a_uio;
+	memset(&path, 0, sizeof(path));
+
+	orig_resid = uio->uio_resid;
+	KASSERT(orig_resid >= 0, ("%s: uio->uio_resid < 0", __func__));
+	if (orig_resid == 0)
+		return (0);
+	KASSERT(uio->uio_offset >= 0, ("%s: uio->uio_offset < 0", __func__));
+	fs = ip->i_e2fs;
+	if (uio->uio_offset < ip->i_size && uio->uio_offset >= fs->e2fs_maxfilesize)
+		return (EOVERFLOW);
+
+	while (uio->uio_resid > 0) {
+		if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
+			break;
+		lbn = lblkno(fs, uio->uio_offset);
+		size = blksize(fs, ip, lbn);
+		blkoffset = blkoff(fs, uio->uio_offset);
+
+		xfersize = fs->e2fs_fsize - blkoffset;
+		xfersize = MIN(xfersize, uio->uio_resid);
+		xfersize = MIN(xfersize, bytesinfile);
+
+		/* get block from ext4 extent cache */
+		cache_type = ext4_ext_in_cache(ip, lbn, &nex);
+		switch (cache_type) {
+		case EXT4_EXT_CACHE_NO:
+			ext4_ext_find_extent(fs, ip, lbn, &path);
+			ep = path.ep_ext;
+			if (ep == NULL)
+				return (EIO);
+
+			ext4_ext_put_cache(ip, ep, EXT4_EXT_CACHE_IN);
+
+			newblk = lbn - ep->e_blk + (ep->e_start_lo |
+			    (daddr_t)ep->e_start_hi << 32);
+
+			if (path.ep_bp != NULL) {
+				brelse(path.ep_bp);
+				path.ep_bp = NULL;
+			}
+			break;
+
+		case EXT4_EXT_CACHE_GAP:
+			/* block has not been allocated yet */
+			return (0);
+
+		case EXT4_EXT_CACHE_IN:
+			newblk = lbn - nex.e_blk + (nex.e_start_lo |
+			    (daddr_t)nex.e_start_hi << 32);
+			break;
+
+		default:
+			panic("%s: invalid cache type", __func__);
+		}
+
+		error = bread(ip->i_devvp, fsbtodb(fs, newblk), size, NOCRED, &bp);
+		if (error) {
+			brelse(bp);
+			return (error);
+		}
+
+		size -= bp->b_resid;
+		if (size < xfersize) {
+			if (size == 0) {
+				bqrelse(bp);
+				break;
+			}
+			xfersize = size;
+		}
+		error = uiomove(bp->b_data + blkoffset, (int)xfersize, uio);
+		bqrelse(bp);
+		if (error)
+			return (error);
+	}
+
+	return (0);
+}
+
+/*
  * Vnode op for writing.
  */
 static int
@@ -1746,7 +1925,7 @@
 	case VDIR:
 		/* XXX differs from ffs -- this is called from ext2_mkdir(). */
 		if ((ioflag & IO_SYNC) == 0)
-		panic("ext2_write: nonsync dir write");
+			panic("ext2_write: nonsync dir write");
 		break;
 	default:
 		panic("ext2_write: type %p %d (%jd,%jd)", (void *)vp,
@@ -1784,10 +1963,10 @@
 		if (uio->uio_offset + xfersize > ip->i_size)
 			vnode_pager_setsize(vp, uio->uio_offset + xfersize);
 
-                /*
+		/*
 		 * We must perform a read-before-write if the transfer size
 		 * does not cover the entire buffer.
-                 */
+		 */
 		if (fs->e2fs_bsize > xfersize)
 			flags |= BA_CLRBUF;
 		else
@@ -1797,16 +1976,7 @@
 		if (error != 0)
 			break;
 
-		/*
-		 * If the buffer is not valid and we did not clear garbage
-		 * out above, we have to do so here even though the write
-		 * covers the entire buffer in order to avoid a mmap()/write
-		 * race where another process may see the garbage prior to
-		 * the uiomove() for a write replacing it.
-		 */
-		if ((bp->b_flags & B_CACHE) == 0 && fs->e2fs_bsize <= xfersize)
-			vfs_bio_clrbuf(bp);
-		if ((ioflag & (IO_SYNC|IO_INVAL)) == (IO_SYNC|IO_INVAL))
+		if ((ioflag & (IO_SYNC | IO_INVAL)) == (IO_SYNC | IO_INVAL))
 			bp->b_flags |= B_NOCACHE;
 		if (uio->uio_offset + xfersize > ip->i_size)
 			ip->i_size = uio->uio_offset + xfersize;
@@ -1816,6 +1986,26 @@
 
 		error =
 		    uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
+		/*
+		 * If the buffer is not already filled and we encounter an
+		 * error while trying to fill it, we have to clear out any
+		 * garbage data from the pages instantiated for the buffer.
+		 * If we do not, a failed uiomove() during a write can leave
+		 * the prior contents of the pages exposed to a userland mmap.
+		 *
+		 * Note that we need only clear buffers with a transfer size
+		 * equal to the block size because buffers with a shorter
+		 * transfer size were cleared above by the call to ext2_balloc()
+		 * with the BA_CLRBUF flag set.
+		 *
+		 * If the source region for uiomove identically mmaps the
+		 * buffer, uiomove() performed the NOP copy, and the buffer
+		 * content remains valid because the page fault handler
+		 * validated the pages.
+		 */
+		if (error != 0 && (bp->b_flags & B_CACHE) == 0 &&
+		    fs->e2fs_bsize == xfersize)
+			vfs_bio_clrbuf(bp);
 		if (ioflag & (IO_VMIO|IO_DIRECT)) {
 			bp->b_flags |= B_RELBUF;
 		}
@@ -1830,7 +2020,7 @@
 		if (ioflag & IO_SYNC) {
 			(void)bwrite(bp);
 		} else if (vm_page_count_severe() ||
-		    buf_dirty_count_severe() ||
+			    buf_dirty_count_severe() ||
 		    (ioflag & IO_ASYNC)) {
 			bp->b_flags |= B_CLUSTEROK;
 			bawrite(bp);
@@ -1837,7 +2027,7 @@
 		} else if (xfersize + blkoffset == fs->e2fs_fsize) {
 			if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0) {
 				bp->b_flags |= B_CLUSTEROK;
-				cluster_write(vp, bp, ip->i_size, seqcount);
+				cluster_write(vp, bp, ip->i_size, seqcount, 0);
 			} else {
 				bawrite(bp);
 			}
@@ -1870,9 +2060,49 @@
 		}
 	}
 	if (uio->uio_resid != resid) {
-               ip->i_flag |= IN_CHANGE | IN_UPDATE;
-               if (ioflag & IO_SYNC)
-                       error = ext2_update(vp, 1);
-       }
+		ip->i_flag |= IN_CHANGE | IN_UPDATE;
+		if (ioflag & IO_SYNC)
+			error = ext2_update(vp, 1);
+	}
 	return (error);
 }
+
+/*
+ * get page routine
+ */
+static int
+ext2_getpages(struct vop_getpages_args *ap)
+{
+	int i;
+	vm_page_t mreq;
+	int pcount;
+
+	pcount = round_page(ap->a_count) / PAGE_SIZE;
+	mreq = ap->a_m[ap->a_reqpage];
+
+	/*
+	 * if ANY DEV_BSIZE blocks are valid on a large filesystem block,
+	 * then the entire page is valid.  Since the page may be mapped,
+	 * user programs might reference data beyond the actual end of file
+	 * occuring within the page.  We have to zero that data.
+	 */
+	VM_OBJECT_WLOCK(mreq->object);
+	if (mreq->valid) {
+		if (mreq->valid != VM_PAGE_BITS_ALL)
+			vm_page_zero_invalid(mreq, TRUE);
+		for (i = 0; i < pcount; i++) {
+			if (i != ap->a_reqpage) {
+				vm_page_lock(ap->a_m[i]);
+				vm_page_free(ap->a_m[i]);
+				vm_page_unlock(ap->a_m[i]);
+			}
+		}
+		VM_OBJECT_WUNLOCK(mreq->object);
+		return VM_PAGER_OK;
+	}
+	VM_OBJECT_WUNLOCK(mreq->object);
+
+	return vnode_pager_generic_getpages(ap->a_vp, ap->a_m,
+					    ap->a_count,
+					    ap->a_reqpage);
+}

Modified: trunk/sys/fs/ext2fs/ext2fs.h
===================================================================
--- trunk/sys/fs/ext2fs/ext2fs.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/ext2fs.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  *  modified for EXT2FS support in Lites 1.1
  *
@@ -4,7 +5,7 @@
  *  Aug 1995, Godmar Back (gback at cs.utah.edu)
  *  University of Utah, Department of Computer Science
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/ext2fs.h 320839 2017-07-09 15:09:15Z pfg $
  */
 /*-
  * Copyright (c) 2009 Aditya Sarawgi
@@ -31,47 +32,15 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * 
+ *
  */
 
 #ifndef _FS_EXT2FS_EXT2FS_H_
-#define _FS_EXT2FS_EXT2FS_H_
+#define	_FS_EXT2FS_EXT2FS_H_
 
 #include <sys/types.h>
 
 /*
- * Maximal count of links to a file
- */
-#define EXT2_LINK_MAX		32000
-
-/*
- * A summary of contiguous blocks of various sizes is maintained
- * in each cylinder group. Normally this is set by the initial
- * value of fs_maxcontig.
- *
- * XXX:FS_MAXCONTIG is set to 16 to conserve space. Here we set
- * EXT2_MAXCONTIG to 32 for better performance.
- */
-#define EXT2_MAXCONTIG		32
-
-/*
- * Constants relative to the data blocks
- */
-#define	EXT2_NDIR_BLOCKS		12
-#define	EXT2_IND_BLOCK			EXT2_NDIR_BLOCKS
-#define	EXT2_DIND_BLOCK			(EXT2_IND_BLOCK + 1)
-#define	EXT2_TIND_BLOCK			(EXT2_DIND_BLOCK + 1)
-#define	EXT2_N_BLOCKS			(EXT2_TIND_BLOCK + 1)
-#define EXT2_MAXSYMLINKLEN		(EXT2_N_BLOCKS * sizeof(uint32_t))
-
-/*
- * The path name on which the file system is mounted is maintained
- * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
- * the super block for this name.
- */
-#define MAXMNTLEN 512
-
-/*
  * Super block for an ext2fs file system.
  */
 struct ext2fs {
@@ -104,12 +73,12 @@
 	uint32_t  e2fs_first_ino;	/* first non-reserved inode */
 	uint16_t  e2fs_inode_size;	/* size of inode structure */
 	uint16_t  e2fs_block_group_nr;	/* block grp number of this sblk*/
-	uint32_t  e2fs_features_compat; /*  compatible feature set */
+	uint32_t  e2fs_features_compat;	/* compatible feature set */
 	uint32_t  e2fs_features_incompat; /* incompatible feature set */
 	uint32_t  e2fs_features_rocompat; /* RO-compatible feature set */
 	uint8_t	  e2fs_uuid[16];	/* 128-bit uuid for volume */
 	char      e2fs_vname[16];	/* volume name */
-	char      e2fs_fsmnt[64]; 	/* name mounted on */
+	char      e2fs_fsmnt[64];	/* name mounted on */
 	uint32_t  e2fs_algo;		/* For compression */
 	uint8_t   e2fs_prealloc;	/* # of blocks for old prealloc */
 	uint8_t   e2fs_dir_prealloc;	/* # of blocks for old prealloc dirs */
@@ -120,27 +89,62 @@
 	uint32_t  e3fs_last_orphan;	/* start of list of inodes to delete */
 	uint32_t  e3fs_hash_seed[4];	/* HTREE hash seed */
 	char      e3fs_def_hash_version; /* Default hash version to use */
-	char      e3fs_reserved_char_pad;
+	char      e3fs_jnl_backup_type;
+	uint16_t  e3fs_desc_size;	/* size of group descriptor */
 	uint32_t  e3fs_default_mount_opts;
 	uint32_t  e3fs_first_meta_bg;	/* First metablock block group */
-	uint32_t  e3fs_mkfs_time;      /* when the fs was created */
-	uint32_t  e3fs_jnl_blks[17];   /* backup of the journal inode */
-	uint32_t  e4fs_bcount_hi;      /* block count */
-	uint32_t  e4fs_rbcount_hi;     /* reserved blocks count */
-	uint32_t  e4fs_fbcount_hi;     /* free blocks count */
-	uint16_t  e4fs_min_extra_isize;/* all inodes have at least some bytes */
+	uint32_t  e3fs_mkfs_time;	/* when the fs was created */
+	uint32_t  e3fs_jnl_blks[17];	/* backup of the journal inode */
+	uint32_t  e4fs_bcount_hi;	/* high bits of blocks count */
+	uint32_t  e4fs_rbcount_hi;	/* high bits of reserved blocks count */
+	uint32_t  e4fs_fbcount_hi;	/* high bits of free blocks count */
+	uint16_t  e4fs_min_extra_isize; /* all inodes have at least some bytes */
 	uint16_t  e4fs_want_extra_isize; /* inodes must reserve some bytes */
-	uint32_t  e4fs_flags;	  /* miscellaneous flags */
-	uint16_t  e4fs_raid_stride;    /* RAID stride */
-	uint16_t  e4fs_mmpintv;	/* number of seconds to wait in MMP checking */
-	uint64_t  e4fs_mmpblk;	 /* block for multi-mount protection */
-	uint32_t  e4fs_raid_stripe_wid;/* blocks on all data disks (N * stride) */
-	uint8_t   e4fs_log_gpf;	/* FLEX_BG group size */ 
-	uint8_t   e4fs_char_pad2;
-	uint16_t  e4fs_pad;
-	uint32_t  reserved2[162];	/* Padding to the end of the block */	
+	uint32_t  e4fs_flags;		/* miscellaneous flags */
+	uint16_t  e4fs_raid_stride;	/* RAID stride */
+	uint16_t  e4fs_mmpintv;		/* number of seconds to wait in MMP checking */
+	uint64_t  e4fs_mmpblk;		/* block for multi-mount protection */
+	uint32_t  e4fs_raid_stripe_wid; /* blocks on all data disks (N * stride) */
+	uint8_t   e4fs_log_gpf;		/* FLEX_BG group size */
+	uint8_t   e4fs_chksum_type;	/* metadata checksum algorithm used */
+	uint8_t   e4fs_encrypt;		/* versioning level for encryption */
+	uint8_t   e4fs_reserved_pad;
+	uint64_t  e4fs_kbytes_written;	/* number of lifetime kilobytes */
+	uint32_t  e4fs_snapinum;	/* inode number of active snapshot */
+	uint32_t  e4fs_snapid;		/* sequential ID of active snapshot */
+	uint64_t  e4fs_snaprbcount;	/* reserved blocks for active snapshot */
+	uint32_t  e4fs_snaplist;	/* inode number for on-disk snapshot */
+	uint32_t  e4fs_errcount;	/* number of file system errors */
+	uint32_t  e4fs_first_errtime;	/* first time an error happened */
+	uint32_t  e4fs_first_errino;	/* inode involved in first error */
+	uint64_t  e4fs_first_errblk;	/* block involved of first error */
+	uint8_t   e4fs_first_errfunc[32]; /* function where error happened */
+	uint32_t  e4fs_first_errline;	/* line number where error happened */
+	uint32_t  e4fs_last_errtime;	/* most recent time of an error */
+	uint32_t  e4fs_last_errino;	/* inode involved in last error */
+	uint32_t  e4fs_last_errline;	/* line number where error happened */
+	uint64_t  e4fs_last_errblk;	/* block involved of last error */
+	uint8_t   e4fs_last_errfunc[32]; /* function where error happened */
+	uint8_t   e4fs_mount_opts[64];
+	uint32_t  e4fs_usrquota_inum;	/* inode for tracking user quota */
+	uint32_t  e4fs_grpquota_inum;	/* inode for tracking group quota */
+	uint32_t  e4fs_overhead_clusters; /* overhead blocks/clusters */
+	uint32_t  e4fs_backup_bgs[2];	/* groups with sparse_super2 SBs */
+	uint8_t   e4fs_encrypt_algos[4]; /* encryption algorithms in use */
+	uint8_t   e4fs_encrypt_pw_salt[16]; /* salt used for string2key */
+	uint32_t  e4fs_lpf_ino;		/* location of the lost+found inode */
+	uint32_t  e4fs_proj_quota_inum;	/* inode for tracking project quota */
+	uint32_t  e4fs_chksum_seed;	/* checksum seed */
+	uint32_t  e4fs_reserved[98];	/* padding to the end of the block */
+	uint32_t  e4fs_sbchksum;	/* superblock checksum */
 };
 
+/*
+ * The path name on which the file system is mounted is maintained
+ * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
+ * the super block for this name.
+ */
+#define	MAXMNTLEN 512
 
 /*
  * In-Memory Superblock
@@ -149,77 +153,89 @@
 struct m_ext2fs {
 	struct ext2fs * e2fs;
 	char     e2fs_fsmnt[MAXMNTLEN];/* name mounted on */
-	char     e2fs_ronly;      /* mounted read-only flag */
-	char     e2fs_fmod;       /* super block modified flag */
-	uint32_t e2fs_bsize;      /* Block size */
-	uint32_t e2fs_bshift;     /* calc of logical block no */
-	int32_t  e2fs_bpg;	  /* Number of blocks per group */
-	int64_t  e2fs_qbmask;     /* = s_blocksize -1 */
-	uint32_t e2fs_fsbtodb;    /* Shift to get disk block */
+	char     e2fs_ronly;	  /* mounted read-only flag */
+	char     e2fs_fmod;	  /* super block modified flag */
+	uint32_t e2fs_bsize;	  /* Block size */
+	uint32_t e2fs_bshift;	  /* calc of logical block no */
+	uint32_t e2fs_bpg;	  /* Number of blocks per group */
+	int64_t  e2fs_qbmask;	  /* = s_blocksize -1 */
+	uint32_t e2fs_fsbtodb;	  /* Shift to get disk block */
 	uint32_t e2fs_ipg;	  /* Number of inodes per group */
 	uint32_t e2fs_ipb;	  /* Number of inodes per block */
-	uint32_t e2fs_itpg;       /* Number of inode table per group */
-	uint32_t e2fs_fsize;      /* Size of fragments per block */
+	uint32_t e2fs_itpg;	  /* Number of inode table per group */
+	uint32_t e2fs_fsize;	  /* Size of fragments per block */
 	uint32_t e2fs_fpb;	  /* Number of fragments per block */
 	uint32_t e2fs_fpg;	  /* Number of fragments per group */
-	uint32_t e2fs_gdbcount;   /* Number of group descriptors */
-	uint32_t e2fs_gcount;     /* Number of groups */
-	int32_t  e2fs_isize;      /* Size of inode */
+	uint32_t e2fs_gdbcount;	  /* Number of group descriptors */
+	uint32_t e2fs_gcount;	  /* Number of groups */
+	uint32_t e2fs_isize;	  /* Size of inode */
 	uint32_t e2fs_total_dir;  /* Total number of directories */
 	uint8_t	*e2fs_contigdirs; /* (u) # of contig. allocated dirs */
-	char     e2fs_wasvalid;   /* valid at mount time */
+	char     e2fs_wasvalid;	  /* valid at mount time */
 	off_t    e2fs_maxfilesize;
 	struct   ext2_gd *e2fs_gd; /* Group Descriptors */
 	int32_t  e2fs_contigsumsize;    /* size of cluster summary array */
 	int32_t *e2fs_maxcluster;       /* max cluster in each cyl group */
 	struct   csum *e2fs_clustersum; /* cluster summary in each cyl group */
+	int32_t  e2fs_uhash;	  /* 3 if hash should be signed, 0 if not */
 };
 
-/*
- * The second extended file system version
- */
-#define E2FS_DATE		"95/08/09"
-#define E2FS_VERSION		"0.5b"
+/* cluster summary information */
 
+struct csum {
+	int8_t   cs_init; /* cluster summary has been initialized */
+	int32_t *cs_sum;  /* cluster summary array */
+};
+
 /*
  * The second extended file system magic number
  */
-#define E2FS_MAGIC		0xEF53
+#define	E2FS_MAGIC		0xEF53
 
 /*
  * Revision levels
  */
-#define E2FS_REV0		0	/* The good old (original) format */
-#define E2FS_REV1		1 	/* V2 format w/ dynamic inode sizes */
+#define	E2FS_REV0		0	/* The good old (original) format */
+#define	E2FS_REV1		1	/* V2 format w/ dynamic inode sizes */
 
-#define E2FS_CURRENT_REV	E2FS_REV0
-#define E2FS_MAX_SUPP_REV	E2FS_REV1
+#define	E2FS_REV0_INODE_SIZE 128
 
-#define E2FS_REV0_INODE_SIZE 128
-
 /*
  * compatible/incompatible features
  */
-#define EXT2F_COMPAT_PREALLOC		0x0001
-#define EXT2F_COMPAT_HASJOURNAL		0x0004
-#define EXT2F_COMPAT_RESIZE		0x0010
-#define EXT2F_COMPAT_DIRHASHINDEX	0x0020
+#define	EXT2F_COMPAT_PREALLOC		0x0001
+#define	EXT2F_COMPAT_HASJOURNAL		0x0004
+#define	EXT2F_COMPAT_RESIZE		0x0010
+#define	EXT2F_COMPAT_DIRHASHINDEX	0x0020
+#define	EXT2F_COMPAT_SPARSESUPER2	0x0200
 
-#define EXT2F_ROCOMPAT_SPARSESUPER	0x0001
-#define EXT2F_ROCOMPAT_LARGEFILE	0x0002
-#define EXT2F_ROCOMPAT_BTREE_DIR	0x0004
-#define EXT2F_ROCOMPAT_HUGE_FILE	0x0008
-#define EXT2F_ROCOMPAT_GDT_CSUM		0x0010
-#define EXT2F_ROCOMPAT_DIR_NLINK	0x0020
-#define EXT2F_ROCOMPAT_EXTRA_ISIZE	0x0040
+#define	EXT2F_ROCOMPAT_SPARSESUPER	0x0001
+#define	EXT2F_ROCOMPAT_LARGEFILE	0x0002
+#define	EXT2F_ROCOMPAT_BTREE_DIR	0x0004
+#define	EXT2F_ROCOMPAT_HUGE_FILE	0x0008
+#define	EXT2F_ROCOMPAT_GDT_CSUM		0x0010
+#define	EXT2F_ROCOMPAT_DIR_NLINK	0x0020
+#define	EXT2F_ROCOMPAT_EXTRA_ISIZE	0x0040
+#define	EXT2F_ROCOMPAT_QUOTA		0x0100
+#define	EXT2F_ROCOMPAT_BIGALLOC		0x0200
+#define	EXT2F_ROCOMPAT_METADATA_CKSUM	0x0400
+#define	EXT2F_ROCOMPAT_READONLY		0x1000
+#define	EXT2F_ROCOMPAT_PROJECT		0x2000
 
-#define EXT2F_INCOMPAT_COMP		0x0001
-#define EXT2F_INCOMPAT_FTYPE		0x0002
-#define EXT2F_INCOMPAT_META_BG		0x0010
-#define EXT2F_INCOMPAT_EXTENTS		0x0040
-#define EXT2F_INCOMPAT_64BIT		0x0080
-#define EXT2F_INCOMPAT_MMP		0x0100
-#define EXT2F_INCOMPAT_FLEX_BG		0x0200
+#define	EXT2F_INCOMPAT_COMP		0x0001
+#define	EXT2F_INCOMPAT_FTYPE		0x0002
+#define	EXT2F_INCOMPAT_RECOVER		0x0004
+#define	EXT2F_INCOMPAT_META_BG		0x0010
+#define	EXT2F_INCOMPAT_EXTENTS		0x0040
+#define	EXT2F_INCOMPAT_64BIT		0x0080
+#define	EXT2F_INCOMPAT_MMP		0x0100
+#define	EXT2F_INCOMPAT_FLEX_BG		0x0200
+#define	EXT2F_INCOMPAT_EA_INODE		0x0400
+#define	EXT2F_INCOMPAT_DIRDATA		0x1000
+#define	EXT2F_INCOMPAT_CSUM_SEED	0x2000
+#define	EXT2F_INCOMPAT_LARGEDIR		0x4000
+#define	EXT2F_INCOMPAT_INLINE_DATA	0x8000
+#define	EXT2F_INCOMPAT_ENCRYPT		0x10000
 
 /*
  * Features supported in this implementation
@@ -227,52 +243,57 @@
  * We support the following REV1 features:
  * - EXT2F_ROCOMPAT_SPARSESUPER
  * - EXT2F_ROCOMPAT_LARGEFILE
+ * - EXT2F_ROCOMPAT_EXTRA_ISIZE
  * - EXT2F_INCOMPAT_FTYPE
+ *
+ * We partially support (read-only) the following EXT4 features:
+ * - EXT2F_ROCOMPAT_HUGE_FILE
+ * - EXT2F_INCOMPAT_EXTENTS
+ *
+ * We do not support these EXT4 features but they are irrelevant
+ * for read-only support:
+ * - EXT2F_INCOMPAT_RECOVER
+ * - EXT2F_INCOMPAT_FLEX_BG
+ * - EXT2F_INCOMPAT_META_BG
  */
-#define EXT2F_COMPAT_SUPP		0x0000
-#define EXT2F_ROCOMPAT_SUPP		(EXT2F_ROCOMPAT_SPARSESUPER | \
+#define	EXT2F_COMPAT_SUPP		EXT2F_COMPAT_DIRHASHINDEX
+#define	EXT2F_ROCOMPAT_SUPP		(EXT2F_ROCOMPAT_SPARSESUPER | \
 					 EXT2F_ROCOMPAT_LARGEFILE | \
+					 EXT2F_ROCOMPAT_HUGE_FILE | \
 					 EXT2F_ROCOMPAT_EXTRA_ISIZE)
-#define EXT2F_INCOMPAT_SUPP		EXT2F_INCOMPAT_FTYPE
+#define	EXT2F_INCOMPAT_SUPP		EXT2F_INCOMPAT_FTYPE
+#define	EXT4F_RO_INCOMPAT_SUPP		(EXT2F_INCOMPAT_EXTENTS | \
+					 EXT2F_INCOMPAT_RECOVER | \
+					 EXT2F_INCOMPAT_FLEX_BG | \
+					 EXT2F_INCOMPAT_META_BG )
 
 /* Assume that user mode programs are passing in an ext2fs superblock, not
  * a kernel struct super_block.  This will allow us to call the feature-test
  * macros from user land. */
-#define EXT2_SB(sb)	(sb)
+#define	EXT2_SB(sb)	(sb)
 
 /*
  * Feature set definitions
  */
-#define EXT2_HAS_COMPAT_FEATURE(sb,mask)			\
+#define	EXT2_HAS_COMPAT_FEATURE(sb,mask)			\
 	( EXT2_SB(sb)->e2fs->e2fs_features_compat & htole32(mask) )
-#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)			\
+#define	EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)			\
 	( EXT2_SB(sb)->e2fs->e2fs_features_rocompat & htole32(mask) )
-#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask)			\
+#define	EXT2_HAS_INCOMPAT_FEATURE(sb,mask)			\
 	( EXT2_SB(sb)->e2fs->e2fs_features_incompat & htole32(mask) )
 
 /*
- * Definitions of behavior on errors
+ * File clean flags
  */
-#define E2FS_BEH_CONTINUE		1	/* continue operation */
-#define E2FS_BEH_READONLY		2	/* remount fs read only */
-#define E2FS_BEH_PANIC			3	/* cause panic */
-#define E2FS_BEH_DEFAULT		E2FS_BEH_CONTINUE
+#define	E2FS_ISCLEAN			0x0001	/* Unmounted cleanly */
+#define	E2FS_ERRORS			0x0002	/* Errors detected */
 
 /*
- * OS identification
+ * Filesystem miscellaneous flags
  */
-#define E2FS_OS_LINUX		0
-#define E2FS_OS_HURD		1
-#define E2FS_OS_MASIX		2
-#define E2FS_OS_FREEBSD		3
-#define E2FS_OS_LITES		4
+#define	E2FS_SIGNED_HASH	0x0001
+#define	E2FS_UNSIGNED_HASH	0x0002
 
-/*
- * File clean flags
- */
-#define	E2FS_ISCLEAN			0x0001	/* Unmounted cleanly */
-#define	E2FS_ERRORS			0x0002	/* Errors detected */
-
 /* ext2 file system block group descriptor */
 
 struct ext2_gd {
@@ -282,49 +303,43 @@
 	uint16_t ext2bgd_nbfree;	/* number of free blocks */
 	uint16_t ext2bgd_nifree;	/* number of free inodes */
 	uint16_t ext2bgd_ndirs;		/* number of directories */
-	uint16_t ext2bgd_flags;		/* block group flags */
-	uint32_t ext2bgd_x_bitmap;	/* snapshot exclusion bitmap loc. */
-	uint16_t ext2bgd_b_bmap_csum;	/* block bitmap checksum */
-	uint16_t ext2bgd_i_bmap_csum;	/* inode bitmap checksum */
-	uint16_t ext2bgd_i_unused;	/* unused inode count */
-	uint16_t ext2bgd_csum;		/* group descriptor checksum */
+	uint16_t ext4bgd_flags;		/* block group flags */
+	uint32_t ext4bgd_x_bitmap;	/* snapshot exclusion bitmap loc. */
+	uint16_t ext4bgd_b_bmap_csum;	/* block bitmap checksum */
+	uint16_t ext4bgd_i_bmap_csum;	/* inode bitmap checksum */
+	uint16_t ext4bgd_i_unused;	/* unused inode count */
+	uint16_t ext4bgd_csum;		/* group descriptor checksum */
 };
 
-/* cluster summary information */
 
-struct csum {
-	int8_t   cs_init; /* cluster summary has been initialized */
-	int32_t *cs_sum;  /* cluster summary array */
-};
-
 /* EXT2FS metadatas are stored in little-endian byte order. These macros
  * helps reading these metadatas
  */
 
-#define e2fs_cgload(old, new, size) memcpy((new), (old), (size));
-#define e2fs_cgsave(old, new, size) memcpy((new), (old), (size));
+#define	e2fs_cgload(old, new, size) memcpy((new), (old), (size));
+#define	e2fs_cgsave(old, new, size) memcpy((new), (old), (size));
 
 /*
  * Macro-instructions used to manage several block sizes
  */
 #define	EXT2_MAX_BLOCK_SIZE		4096
-#define EXT2_MIN_BLOCK_LOG_SIZE		  10
-#define EXT2_BLOCK_SIZE(s)		((s)->e2fs_bsize)
+#define	EXT2_MIN_BLOCK_LOG_SIZE		  10
+#define	EXT2_BLOCK_SIZE(s)		((s)->e2fs_bsize)
 #define	EXT2_ADDR_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof(uint32_t))
-#define EXT2_INODE_SIZE(s)		(EXT2_SB(s)->e2fs_isize)
+#define	EXT2_INODE_SIZE(s)		(EXT2_SB(s)->e2fs_isize)
 
 /*
  * Macro-instructions used to manage fragments
  */
-#define EXT2_MIN_FRAG_SIZE		1024
+#define	EXT2_MIN_FRAG_SIZE		1024
 #define	EXT2_MAX_FRAG_SIZE		4096
-#define EXT2_MIN_FRAG_LOG_SIZE		  10
-#define EXT2_FRAG_SIZE(s)		(EXT2_SB(s)->e2fs_fsize)
-#define EXT2_FRAGS_PER_BLOCK(s)		(EXT2_SB(s)->e2fs_fpb)
+#define	EXT2_MIN_FRAG_LOG_SIZE		  10
+#define	EXT2_FRAG_SIZE(s)		(EXT2_SB(s)->e2fs_fsize)
+#define	EXT2_FRAGS_PER_BLOCK(s)		(EXT2_SB(s)->e2fs_fpb)
 
 /*
  * Macro-instructions used to manage group descriptors
  */
-#define EXT2_BLOCKS_PER_GROUP(s)	(EXT2_SB(s)->e2fs_bpg)
+#define	EXT2_BLOCKS_PER_GROUP(s)	(EXT2_SB(s)->e2fs_bpg)
 
 #endif	/* !_FS_EXT2FS_EXT2FS_H_ */

Modified: trunk/sys/fs/ext2fs/fs.h
===================================================================
--- trunk/sys/fs/ext2fs/fs.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/fs.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  *  modified for EXT2FS support in Lites 1.1
  *
@@ -33,11 +34,11 @@
  * SUCH DAMAGE.
  *
  *	@(#)fs.h	8.7 (Berkeley) 4/19/94
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/fs.h 311232 2017-01-04 02:43:33Z pfg $
  */
 
 #ifndef _FS_EXT2FS_FS_H_
-#define _FS_EXT2FS_FS_H_
+#define	_FS_EXT2FS_FS_H_
 
 /*
  * Each disk drive contains some number of file systems.
@@ -54,17 +55,27 @@
  * The first boot and super blocks are given in absolute disk addresses.
  * The byte-offset forms are preferred, as they don't imply a sector size.
  */
-#define SBSIZE		1024
-#define SBLOCK		2
+#define	SBSIZE		1024
+#define	SBLOCK		2
 
 /*
  * The path name on which the file system is mounted is maintained
- * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in 
- * the super block for this name. 
+ * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in
+ * the super block for this name.
  */
-#define MAXMNTLEN	512
+#define	MAXMNTLEN	512
 
 /*
+ * A summary of contiguous blocks of various sizes is maintained
+ * in each cylinder group. Normally this is set by the initial
+ * value of fs_maxcontig.
+ *
+ * XXX:FS_MAXCONTIG is set to 16 to conserve space. Here we set
+ * EXT2_MAXCONTIG to 32 for better performance.
+ */
+#define	EXT2_MAXCONTIG	32
+
+/*
  * Grigoriy Orlov <gluk at ptci.ru> has done some extensive work to fine
  * tune the layout preferences for directories within a filesystem.
  * His algorithm can be tuned by adjusting the following parameters
@@ -72,13 +83,13 @@
  * of files per directory. These defaults are well selected for typical
  * filesystems, but may need to be tuned for odd cases like filesystems
  * being used for squid caches or news spools.
- * AVFPDIR is the expected number of files per directory. AVGDIRSIZE is 
- * obtained by multiplying AVFPDIR and AVFILESIZ which is assumed to be 
+ * AVFPDIR is the expected number of files per directory. AVGDIRSIZE is
+ * obtained by multiplying AVFPDIR and AVFILESIZ which is assumed to be
  * 16384.
  */
 
-#define AFPDIR		64
-#define AVGDIRSIZE	1048576
+#define	AFPDIR		64
+#define	AVGDIRSIZE	1048576
 
 /*
  * Macros for access to superblock array structures
@@ -88,14 +99,14 @@
  * Turn file system block numbers into disk block addresses.
  * This maps file system blocks to device size blocks.
  */
-#define fsbtodb(fs, b)	((b) << ((fs)->e2fs_fsbtodb))
-#define	dbtofsb(fs, b)	((b) >> ((fs)->e2fs_fsbtodb))
+#define	fsbtodb(fs, b)	((daddr_t)(b) << (fs)->e2fs_fsbtodb)
+#define	dbtofsb(fs, b)	((b) >> (fs)->e2fs_fsbtodb)
 
 /* get group containing inode */
-#define ino_to_cg(fs, x)	(((x) - 1) / (fs->e2fs_ipg))
+#define	ino_to_cg(fs, x)	(((x) - 1) / (fs->e2fs_ipg))
 
 /* get block containing inode from its number x */
-#define ino_to_fsba(fs, x)                                              \
+#define	ino_to_fsba(fs, x)                                              \
         ((fs)->e2fs_gd[ino_to_cg((fs), (x))].ext2bgd_i_tables +         \
         (((x) - 1) % (fs)->e2fs->e2fs_ipg) / (fs)->e2fs_ipb)
 
@@ -116,20 +127,20 @@
  * quantities by using shifts and masks in place of divisions
  * modulos and multiplications.
  */
-#define blkoff(fs, loc)		/* calculates (loc % fs->fs_bsize) */ \
+#define	blkoff(fs, loc)		/* calculates (loc % fs->fs_bsize) */ \
 	((loc) & (fs)->e2fs_qbmask)
 
-#define lblktosize(fs, blk)	/* calculates (blk * fs->fs_bsize) */ \
+#define	lblktosize(fs, blk)	/* calculates (blk * fs->fs_bsize) */ \
 	((blk) << (fs->e2fs_bshift))
 
-#define lblkno(fs, loc)		/* calculates (loc / fs->fs_bsize) */ \
+#define	lblkno(fs, loc)		/* calculates (loc / fs->fs_bsize) */ \
 	((loc) >> (fs->e2fs_bshift))
 
 /* no fragments -> logical block number equal # of frags */
-#define numfrags(fs, loc)	/* calculates (loc / fs->fs_fsize) */ \
+#define	numfrags(fs, loc)	/* calculates (loc / fs->fs_fsize) */ \
 	((loc) >> (fs->e2fs_bshift))
 
-#define fragroundup(fs, size)	/* calculates roundup(size, fs->fs_fsize) */ \
+#define	fragroundup(fs, size)	/* calculates roundup(size, fs->fs_fsize) */ \
 	roundup(size, fs->e2fs_fsize)
 	/* was (((size) + (fs)->fs_qfmask) & (fs)->fs_fmask) */
 
@@ -137,7 +148,7 @@
  * Determining the size of a file block in the file system.
  * easy w/o fragments
  */
-#define blksize(fs, ip, lbn) ((fs)->e2fs_fsize)
+#define	blksize(fs, ip, lbn) ((fs)->e2fs_fsize)
 
 /*
  * INOPB is the number of inodes in a secondary storage block.
@@ -149,4 +160,4 @@
  */
 #define	NINDIR(fs)	(EXT2_ADDR_PER_BLOCK(fs))
 
-#endif /* !_FS_EXT2FS_FS_H_ */
+#endif	/* !_FS_EXT2FS_FS_H_ */

Added: trunk/sys/fs/ext2fs/htree.h
===================================================================
--- trunk/sys/fs/ext2fs/htree.h	                        (rev 0)
+++ trunk/sys/fs/ext2fs/htree.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -0,0 +1,101 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2010, 2012 Zheng Liu <lz at freebsd.org>
+ * Copyright (c) 2012, Vyacheslav Matyushin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: stable/10/sys/fs/ext2fs/htree.h 311232 2017-01-04 02:43:33Z pfg $
+ */
+
+#ifndef _FS_EXT2FS_HTREE_H_
+#define	_FS_EXT2FS_HTREE_H_
+
+/* EXT3 HTree directory indexing */
+
+#define	EXT2_HTREE_LEGACY		0
+#define	EXT2_HTREE_HALF_MD4		1
+#define	EXT2_HTREE_TEA			2
+#define	EXT2_HTREE_LEGACY_UNSIGNED	3
+#define	EXT2_HTREE_HALF_MD4_UNSIGNED	4
+#define	EXT2_HTREE_TEA_UNSIGNED		5
+
+#define	EXT2_HTREE_EOF 0x7FFFFFFF
+
+struct ext2fs_fake_direct {
+	uint32_t e2d_ino;		/* inode number of entry */
+	uint16_t e2d_reclen;		/* length of this record */
+	uint8_t	e2d_namlen;		/* length of string in d_name */
+	uint8_t	e2d_type;		/* file type */
+};
+
+struct ext2fs_htree_count {
+	uint16_t h_entries_max;
+	uint16_t h_entries_num;
+};
+
+struct ext2fs_htree_entry {
+	uint32_t h_hash;
+	uint32_t h_blk;
+};
+
+struct ext2fs_htree_root_info {
+	uint32_t h_reserved1;
+	uint8_t	h_hash_version;
+	uint8_t	h_info_len;
+	uint8_t	h_ind_levels;
+	uint8_t	h_reserved2;
+};
+
+struct ext2fs_htree_root {
+	struct ext2fs_fake_direct h_dot;
+	char	h_dot_name[4];
+	struct ext2fs_fake_direct h_dotdot;
+	char	h_dotdot_name[4];
+	struct ext2fs_htree_root_info h_info;
+	struct ext2fs_htree_entry h_entries[0];
+};
+
+struct ext2fs_htree_node {
+	struct ext2fs_fake_direct h_fake_dirent;
+	struct ext2fs_htree_entry h_entries[0];
+};
+
+struct ext2fs_htree_lookup_level {
+	struct buf *h_bp;
+	struct ext2fs_htree_entry *h_entries;
+	struct ext2fs_htree_entry *h_entry;
+};
+
+struct ext2fs_htree_lookup_info {
+	struct ext2fs_htree_lookup_level h_levels[2];
+	uint32_t h_levels_num;
+};
+
+struct ext2fs_htree_sort_entry {
+	uint16_t h_offset;
+	uint16_t h_size;
+	uint32_t h_hash;
+};
+
+#endif	/* !_FS_EXT2FS_HTREE_H_ */


Property changes on: trunk/sys/fs/ext2fs/htree.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/sys/fs/ext2fs/inode.h
===================================================================
--- trunk/sys/fs/ext2fs/inode.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/ext2fs/inode.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1982, 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -32,17 +33,18 @@
  * SUCH DAMAGE.
  *
  *	@(#)inode.h	8.9 (Berkeley) 5/14/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/ext2fs/inode.h 311232 2017-01-04 02:43:33Z pfg $
  */
 
 #ifndef _FS_EXT2FS_INODE_H_
 #define	_FS_EXT2FS_INODE_H_
 
+#include <sys/param.h>
 #include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/queue.h>
 
-#define	NDADDR	12			/* Direct addresses in inode. */
-#define	NIADDR	3			/* Indirect addresses in inode. */
+#include <fs/ext2fs/ext2_extents.h>
 
 /*
  * This must agree with the definition in <ufs/ufs/dir.h>.
@@ -49,7 +51,17 @@
  */
 #define	doff_t		int32_t
 
+#define	NDADDR	12			/* Direct addresses in inode. */
+#define	NIADDR	3			/* Indirect addresses in inode. */
+
 /*
+ * The size of physical and logical block numbers in EXT2FS.
+ */
+typedef uint32_t e2fs_daddr_t;
+typedef int64_t e2fs_lbn_t;
+typedef int64_t e4fs_daddr_t;
+
+/*
  * The inode is used to describe each active (or recently active) file in the
  * EXT2FS filesystem. It is composed of two types of information. The first
  * part is the information that is needed only while the file is active (such
@@ -81,7 +93,10 @@
 	/* Fields from struct dinode in UFS. */
 	uint16_t	i_mode;		/* IFMT, permissions; see below. */
 	int16_t		i_nlink;	/* File link count. */
+	uint32_t	i_uid;		/* File owner. */
+	uint32_t	i_gid;		/* File group. */
 	uint64_t	i_size;		/* File byte count. */
+	uint64_t	i_blocks;	/* Blocks actually held. */
 	int32_t		i_atime;	/* Last access time. */
 	int32_t		i_mtime;	/* Last modified time. */
 	int32_t		i_ctime;	/* Last inode change time. */
@@ -90,13 +105,12 @@
 	int32_t		i_atimensec;	/* Last access time. */
 	int32_t		i_ctimensec;	/* Last inode change time. */
 	int32_t		i_birthnsec;	/* Inode creation time. */
+	uint32_t	i_gen;		/* Generation number. */
+	uint32_t	i_flags;	/* Status flags (chflags). */
 	uint32_t	i_db[NDADDR];	/* Direct disk blocks. */
 	uint32_t	i_ib[NIADDR];	/* Indirect disk blocks. */
-	uint32_t	i_flags;	/* Status flags (chflags). */
-	uint32_t	i_blocks;	/* Blocks actually held. */
-	uint32_t	i_gen;		/* Generation number. */
-	uint32_t	i_uid;		/* File owner. */
-	uint32_t	i_gid;		/* File group. */
+
+	struct ext4_extent_cache i_ext_cache; /* cache for ext4 extent */
 };
 
 /*
@@ -137,9 +151,16 @@
 #define	IN_HASHED	0x0020		/* Inode is on hash list */
 #define	IN_LAZYMOD	0x0040		/* Modified, but don't write yet. */
 #define	IN_SPACECOUNTED	0x0080		/* Blocks to be freed in free count. */
-#define IN_LAZYACCESS   0x0100		/* Process IN_ACCESS after the
+#define	IN_LAZYACCESS   0x0100		/* Process IN_ACCESS after the
 					    suspension finished */
 
+/*
+ * These are translation flags for some attributes that Ext4
+ * passes as inode flags but that we cannot pass directly.
+ */
+#define	IN_E3INDEX	0x010000
+#define	IN_E4EXTENTS	0x020000
+
 #define i_devvp i_ump->um_devvp
 
 #ifdef _KERNEL
@@ -148,7 +169,7 @@
  * ext2_getlbns and used by truncate and bmap code.
  */
 struct indir {
-	int32_t in_lbn;			/* Logical block number. */
+	e2fs_lbn_t in_lbn;		/* Logical block number. */
 	int	in_off;			/* Offset in buffer. */
 };
 
@@ -158,11 +179,11 @@
 
 /* This overlays the fid structure (see mount.h). */
 struct ufid {
-	uint16_t ufid_len;	/* Length of structure. */
-	uint16_t ufid_pad;	/* Force 32-bit alignment. */
-	ino_t	 ufid_ino;	/* File number (ino). */
-	uint32_t ufid_gen;	/* Generation number. */
+	uint16_t ufid_len;		/* Length of structure. */
+	uint16_t ufid_pad;		/* Force 32-bit alignment. */
+	ino_t	ufid_ino;		/* File number (ino). */
+	uint32_t ufid_gen;		/* Generation number. */
 };
-#endif /* _KERNEL */
+#endif	/* _KERNEL */
 
-#endif /* !_FS_EXT2FS_INODE_H_ */
+#endif	/* !_FS_EXT2FS_INODE_H_ */

Modified: trunk/sys/fs/fdescfs/fdesc.h
===================================================================
--- trunk/sys/fs/fdescfs/fdesc.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/fdescfs/fdesc.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1992, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -31,7 +32,7 @@
  *
  *	@(#)fdesc.h	8.5 (Berkeley) 1/21/94
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/fdescfs/fdesc.h 191990 2009-05-11 15:33:26Z attilio $
  */
 
 #ifdef _KERNEL

Modified: trunk/sys/fs/fdescfs/fdesc_vfsops.c
===================================================================
--- trunk/sys/fs/fdescfs/fdesc_vfsops.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/fdescfs/fdesc_vfsops.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1992, 1993, 1995
  *	The Regents of the University of California.  All rights reserved.
@@ -31,7 +32,7 @@
  *
  *	@(#)fdesc_vfsops.c	8.4 (Berkeley) 1/21/94
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/fdescfs/fdesc_vfsops.c 277985 2015-01-31 17:35:53Z jamie $
  */
 
 /*
@@ -42,6 +43,7 @@
 #include <sys/systm.h>
 #include <sys/filedesc.h>
 #include <sys/kernel.h>
+#include <sys/jail.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/malloc.h>
@@ -78,8 +80,12 @@
 {
 	int error = 0;
 	struct fdescmount *fmp;
+	struct thread *td = curthread;
 	struct vnode *rvp;
 
+	if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_FDESCFS))
+		return (EPERM);
+
 	/*
 	 * Update is a no-op
 	 */
@@ -98,7 +104,7 @@
 	error = fdesc_allocvp(Froot, -1, FD_ROOT, mp, &rvp);
 	if (error) {
 		free(fmp, M_FDESCMNT);
-		mp->mnt_data = 0;
+		mp->mnt_data = NULL;
 		return (error);
 	}
 	rvp->v_type = VDIR;
@@ -107,9 +113,6 @@
 	VOP_UNLOCK(rvp, 0);
 	/* XXX -- don't mark as local to work around fts() problems */
 	/*mp->mnt_flag |= MNT_LOCAL;*/
-	MNT_ILOCK(mp);
-	mp->mnt_kern_flag |= MNTK_MPSAFE;
-	MNT_IUNLOCK(mp);
 	vfs_getnewfsid(mp);
 
 	vfs_mountedfrom(mp, "fdescfs");
@@ -152,7 +155,7 @@
 	 */
 	mtx_lock(&fdesc_hashmtx);
 	data = mp->mnt_data;
-	mp->mnt_data = 0;
+	mp->mnt_data = NULL;
 	mtx_unlock(&fdesc_hashmtx);
 	free(data, M_FDESCMNT);	/* XXX */
 
@@ -208,7 +211,7 @@
 	last = min(fdp->fd_nfiles, lim);
 	freefd = 0;
 	for (i = fdp->fd_freefile; i < last; i++)
-		if (fdp->fd_ofiles[i] == NULL)
+		if (fdp->fd_ofiles[i].fde_file == NULL)
 			freefd++;
 
 	/*
@@ -240,4 +243,4 @@
 	.vfs_unmount =		fdesc_unmount,
 };
 
-VFS_SET(fdesc_vfsops, fdescfs, VFCF_SYNTHETIC);
+VFS_SET(fdesc_vfsops, fdescfs, VFCF_SYNTHETIC | VFCF_JAIL);

Modified: trunk/sys/fs/fdescfs/fdesc_vnops.c
===================================================================
--- trunk/sys/fs/fdescfs/fdesc_vnops.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/fdescfs/fdesc_vnops.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1992, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -31,7 +32,7 @@
  *
  *	@(#)fdesc_vnops.c	8.9 (Berkeley) 1/21/94
  *
- * $MidnightBSD: src/sys/fs/fdescfs/fdesc_vnops.c,v 1.6 2013/01/06 17:29:31 laffer1 Exp $
+ * $FreeBSD: stable/10/sys/fs/fdescfs/fdesc_vnops.c 280258 2015-03-19 13:37:36Z rwatson $
  */
 
 /*
@@ -40,7 +41,7 @@
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/capability.h>
+#include <sys/capsicum.h>
 #include <sys/conf.h>
 #include <sys/dirent.h>
 #include <sys/filedesc.h>
@@ -247,6 +248,28 @@
 	return (0);
 }
 
+struct fdesc_get_ino_args {
+	fdntype ftype;
+	unsigned fd_fd;
+	int ix;
+	struct file *fp;
+	struct thread *td;
+};
+
+static int
+fdesc_get_ino_alloc(struct mount *mp, void *arg, int lkflags,
+    struct vnode **rvp)
+{
+	struct fdesc_get_ino_args *a;
+	int error;
+
+	a = arg;
+	error = fdesc_allocvp(a->ftype, a->fd_fd, a->ix, mp, rvp);
+	fdrop(a->fp, a->td);
+	return (error);
+}
+
+
 /*
  * vp is the current namei directory
  * ndp is the name to locate in that directory...
@@ -265,6 +288,7 @@
 	char *pname = cnp->cn_nameptr;
 	struct thread *td = cnp->cn_thread;
 	struct file *fp;
+	struct fdesc_get_ino_args arg;
 	int nlen = cnp->cn_namelen;
 	u_int fd, fd1;
 	int error;
@@ -309,7 +333,7 @@
 	/*
 	 * No rights to check since 'fp' isn't actually used.
 	 */
-	if ((error = fget(td, fd, 0, &fp)) != 0)
+	if ((error = fget(td, fd, NULL, &fp)) != 0)
 		goto bad;
 
 	/* Check if we're looking up ourselves. */
@@ -326,6 +350,8 @@
 		vn_lock(dvp, LK_RETRY | LK_EXCLUSIVE);
 		vdrop(dvp);
 		fvp = dvp;
+		if ((dvp->v_iflag & VI_DOOMED) != 0)
+			error = ENOENT;
 	} else {
 		/*
 		 * Unlock our root node (dvp) when doing this, since we might
@@ -333,18 +359,15 @@
 		 * and the root vnode lock will be obtained afterwards (in case
 		 * we're looking up the fd of the root vnode), which will be the
 		 * opposite lock order. Vhold the root vnode first so we don't
-		 * loose it.
+		 * lose it.
 		 */
-		vhold(dvp);
-		VOP_UNLOCK(dvp, 0);
-		error = fdesc_allocvp(Fdesc, fd, FD_DESC + fd, dvp->v_mount,
-		    &fvp);
-		fdrop(fp, td);
-		/*
-		 * The root vnode must be locked last to prevent deadlock condition.
-		 */
-		vn_lock(dvp, LK_RETRY | LK_EXCLUSIVE);
-		vdrop(dvp);
+		arg.ftype = Fdesc;
+		arg.fd_fd = fd;
+		arg.ix = FD_DESC + fd;
+		arg.fp = fp;
+		arg.td = td;
+		error = vn_vget_ino_gen(dvp, fdesc_get_ino_alloc, &arg,
+		    LK_EXCLUSIVE, &fvp);
 	}
 	
 	if (error)
@@ -445,6 +468,7 @@
 	struct mount *mp;
 	struct file *fp;
 	struct thread *td = curthread;
+	cap_rights_t rights;
 	unsigned fd;
 	int error;
 
@@ -459,7 +483,8 @@
 	/*
 	 * Allow setattr where there is an underlying vnode.
 	 */
-	error = getvnode(td->td_proc->p_fd, fd, CAP_EXTATTR_SET, &fp);
+	error = getvnode(td->td_proc->p_fd, fd,
+	    cap_rights_init(&rights, CAP_EXTATTR_SET), &fp);
 	if (error) {
 		/*
 		 * getvnode() returns EINVAL if the file descriptor is not
@@ -534,7 +559,7 @@
 			dp->d_type = DT_DIR;
 			break;
 		default:
-			if (fdp->fd_ofiles[fcnt] == NULL)
+			if (fdp->fd_ofiles[fcnt].fde_file == NULL)
 				break;
 			dp->d_namlen = sprintf(dp->d_name, "%d", fcnt);
 			dp->d_reclen = UIO_MX;

Modified: trunk/sys/fs/fifofs/fifo_vnops.c
===================================================================
--- trunk/sys/fs/fifofs/fifo_vnops.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/fifofs/fifo_vnops.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,7 +1,9 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1990, 1993, 1995
  *	The Regents of the University of California.
  * Copyright (c) 2005 Robert N. M. Watson
+ * Copyright (c) 2012 Giovanni Trematerra
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -29,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)fifo_vnops.c	8.10 (Berkeley) 5/27/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/sys/fs/fifofs/fifo_vnops.c 288282 2015-09-27 01:06:45Z kib $
  */
 
 #include <sys/param.h>
@@ -42,55 +44,29 @@
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/malloc.h>
-#include <sys/poll.h>
+#include <sys/selinfo.h>
+#include <sys/pipe.h>
 #include <sys/proc.h>
 #include <sys/signalvar.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
 #include <sys/sx.h>
 #include <sys/systm.h>
 #include <sys/un.h>
 #include <sys/unistd.h>
 #include <sys/vnode.h>
-#include <fs/fifofs/fifo.h>
 
-static fo_rdwr_t        fifo_read_f;
-static fo_rdwr_t        fifo_write_f;
-static fo_ioctl_t       fifo_ioctl_f;
-static fo_poll_t        fifo_poll_f;
-static fo_kqfilter_t    fifo_kqfilter_f;
-static fo_stat_t        fifo_stat_f;
-static fo_close_t       fifo_close_f;
-static fo_truncate_t    fifo_truncate_f;
-
-struct fileops fifo_ops_f = {
-	.fo_read =      fifo_read_f,
-	.fo_write =     fifo_write_f,
-	.fo_truncate =  fifo_truncate_f,
-	.fo_ioctl =     fifo_ioctl_f,
-	.fo_poll =      fifo_poll_f,
-	.fo_kqfilter =  fifo_kqfilter_f,
-	.fo_stat =      fifo_stat_f,
-	.fo_close =     fifo_close_f,
-	.fo_chmod =	vn_chmod,
-	.fo_chown =	vn_chown,
-	.fo_flags =     DFLAG_PASSABLE
-};
-
 /*
  * This structure is associated with the FIFO vnode and stores
  * the state associated with the FIFO.
  * Notes about locking:
- *   - fi_readsock and fi_writesock are invariant since init time.
- *   - fi_readers and fi_writers are vnode lock protected.
- *   - fi_wgen is fif_mtx lock protected.
+ *   - fi_pipe is invariant since init time.
+ *   - fi_readers and fi_writers are protected by the vnode lock.
  */
 struct fifoinfo {
-	struct socket	*fi_readsock;
-	struct socket	*fi_writesock;
-	long		fi_readers;
-	long		fi_writers;
-	int		fi_wgen;
+	struct pipe *fi_pipe;
+	long	fi_readers;
+	long	fi_writers;
+	u_int	fi_rgen;
+	u_int	fi_wgen;
 };
 
 static vop_print_t	fifo_print;
@@ -99,29 +75,6 @@
 static vop_pathconf_t	fifo_pathconf;
 static vop_advlock_t	fifo_advlock;
 
-static void	filt_fifordetach(struct knote *kn);
-static int	filt_fiforead(struct knote *kn, long hint);
-static void	filt_fifowdetach(struct knote *kn);
-static int	filt_fifowrite(struct knote *kn, long hint);
-static void	filt_fifodetach_notsup(struct knote *kn);
-static int	filt_fifo_notsup(struct knote *kn, long hint);
-
-static struct filterops fiforead_filtops = {
-	.f_isfd = 1,
-	.f_detach = filt_fifordetach,
-	.f_event = filt_fiforead,
-};
-static struct filterops fifowrite_filtops = {
-	.f_isfd = 1,
-	.f_detach = filt_fifowdetach,
-	.f_event = filt_fifowrite,
-};
-static struct filterops fifo_notsup_filtops = {
-	.f_isfd = 1,
-	.f_detach = filt_fifodetach_notsup,
-	.f_event = filt_fifo_notsup,
-};
-
 struct vop_vector fifo_specops = {
 	.vop_default =		&default_vnodeops,
 
@@ -150,9 +103,6 @@
 	.vop_write =		VOP_PANIC,
 };
 
-struct mtx fifo_mtx;
-MTX_SYSINIT(fifo, &fifo_mtx, "fifo mutex", MTX_DEF);
-
 /*
  * Dispose of fifo resources.
  */
@@ -159,13 +109,13 @@
 static void
 fifo_cleanup(struct vnode *vp)
 {
-	struct fifoinfo *fip = vp->v_fifoinfo;
+	struct fifoinfo *fip;
 
 	ASSERT_VOP_ELOCKED(vp, "fifo_cleanup");
+	fip = vp->v_fifoinfo;
 	if (fip->fi_readers == 0 && fip->fi_writers == 0) {
 		vp->v_fifoinfo = NULL;
-		(void)soclose(fip->fi_readsock);
-		(void)soclose(fip->fi_writesock);
+		pipe_dtor(fip->fi_pipe);
 		free(fip, M_VNODE);
 	}
 }
@@ -185,101 +135,85 @@
 		struct file *a_fp;
 	} */ *ap;
 {
-	struct vnode *vp = ap->a_vp;
+	struct vnode *vp;
+	struct file *fp;
+	struct thread *td;
 	struct fifoinfo *fip;
-	struct thread *td = ap->a_td;
-	struct ucred *cred = ap->a_cred;
-	struct file *fp = ap->a_fp;
-	struct socket *rso, *wso;
-	int error;
+	struct pipe *fpipe;
+	u_int gen;
+	int error, stops_deferred;
 
+	vp = ap->a_vp;
+	fp = ap->a_fp;
+	td = ap->a_td;
 	ASSERT_VOP_ELOCKED(vp, "fifo_open");
-	if (fp == NULL)
+	if (fp == NULL || (ap->a_mode & FEXEC) != 0)
 		return (EINVAL);
 	if ((fip = vp->v_fifoinfo) == NULL) {
+		pipe_named_ctor(&fpipe, td);
 		fip = malloc(sizeof(*fip), M_VNODE, M_WAITOK);
-		error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0, cred, td);
-		if (error)
-			goto fail1;
-		fip->fi_readsock = rso;
-		error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0, cred, td);
-		if (error)
-			goto fail2;
-		fip->fi_writesock = wso;
-		error = soconnect2(wso, rso);
-		/* Close the direction we do not use, so we can get POLLHUP. */
-		if (error == 0)
-			error = soshutdown(rso, SHUT_WR);
-		if (error) {
-			(void)soclose(wso);
-fail2:
-			(void)soclose(rso);
-fail1:
-			free(fip, M_VNODE);
-			return (error);
-		}
-		fip->fi_wgen = fip->fi_readers = fip->fi_writers = 0;
-		wso->so_snd.sb_lowat = PIPE_BUF;
-		SOCKBUF_LOCK(&rso->so_rcv);
-		rso->so_rcv.sb_state |= SBS_CANTRCVMORE;
-		SOCKBUF_UNLOCK(&rso->so_rcv);
-		KASSERT(vp->v_fifoinfo == NULL,
-		    ("fifo_open: v_fifoinfo race"));
+		fip->fi_pipe = fpipe;
+		fpipe->pipe_wgen = fip->fi_readers = fip->fi_writers = 0;
+ 		KASSERT(vp->v_fifoinfo == NULL, ("fifo_open: v_fifoinfo race"));
 		vp->v_fifoinfo = fip;
 	}
+	fpipe = fip->fi_pipe;
+ 	KASSERT(fpipe != NULL, ("fifo_open: pipe is NULL"));
 
 	/*
-	 * Use the fifo_mtx lock here, in addition to the vnode lock,
+	 * Use the pipe mutex here, in addition to the vnode lock,
 	 * in order to allow vnode lock dropping before msleep() calls
 	 * and still avoiding missed wakeups.
 	 */
-	mtx_lock(&fifo_mtx);
+	PIPE_LOCK(fpipe);
 	if (ap->a_mode & FREAD) {
 		fip->fi_readers++;
+		fip->fi_rgen++;
 		if (fip->fi_readers == 1) {
-			SOCKBUF_LOCK(&fip->fi_writesock->so_snd);
-			fip->fi_writesock->so_snd.sb_state &= ~SBS_CANTSENDMORE;
-			SOCKBUF_UNLOCK(&fip->fi_writesock->so_snd);
-			if (fip->fi_writers > 0) {
+			fpipe->pipe_state &= ~PIPE_EOF;
+			if (fip->fi_writers > 0)
 				wakeup(&fip->fi_writers);
-				sowwakeup(fip->fi_writesock);
-			}
 		}
-		fp->f_seqcount = fip->fi_wgen - fip->fi_writers;
+		fp->f_seqcount = fpipe->pipe_wgen - fip->fi_writers;
 	}
 	if (ap->a_mode & FWRITE) {
 		if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) {
-			mtx_unlock(&fifo_mtx);
+			PIPE_UNLOCK(fpipe);
 			if (fip->fi_writers == 0)
 				fifo_cleanup(vp);
 			return (ENXIO);
 		}
 		fip->fi_writers++;
+		fip->fi_wgen++;
 		if (fip->fi_writers == 1) {
-			SOCKBUF_LOCK(&fip->fi_readsock->so_rcv);
-			fip->fi_readsock->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
-			SOCKBUF_UNLOCK(&fip->fi_readsock->so_rcv);
-			if (fip->fi_readers > 0) {
+			fpipe->pipe_state &= ~PIPE_EOF;
+			if (fip->fi_readers > 0)
 				wakeup(&fip->fi_readers);
-				sorwakeup(fip->fi_readsock);
-			}
 		}
 	}
 	if ((ap->a_mode & O_NONBLOCK) == 0) {
 		if ((ap->a_mode & FREAD) && fip->fi_writers == 0) {
+			gen = fip->fi_wgen;
 			VOP_UNLOCK(vp, 0);
-			error = msleep(&fip->fi_readers, &fifo_mtx,
+			stops_deferred = sigallowstop();
+			error = msleep(&fip->fi_readers, PIPE_MTX(fpipe),
 			    PDROP | PCATCH | PSOCK, "fifoor", 0);
+			if (stops_deferred)
+				sigdeferstop();
 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
-			if (error) {
+			if (error != 0 && gen == fip->fi_wgen) {
 				fip->fi_readers--;
 				if (fip->fi_readers == 0) {
-					socantsendmore(fip->fi_writesock);
+					PIPE_LOCK(fpipe);
+					fpipe->pipe_state |= PIPE_EOF;
+					if (fpipe->pipe_state & PIPE_WANTW)
+						wakeup(fpipe);
+					PIPE_UNLOCK(fpipe);
 					fifo_cleanup(vp);
 				}
 				return (error);
 			}
-			mtx_lock(&fifo_mtx);
+			PIPE_LOCK(fpipe);
 			/*
 			 * We must have got woken up because we had a writer.
 			 * That (and not still having one) is the condition
@@ -287,17 +221,23 @@
 			 */
 		}
 		if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) {
+			gen = fip->fi_rgen;
 			VOP_UNLOCK(vp, 0);
-			error = msleep(&fip->fi_writers, &fifo_mtx,
+			stops_deferred = sigallowstop();
+			error = msleep(&fip->fi_writers, PIPE_MTX(fpipe),
 			    PDROP | PCATCH | PSOCK, "fifoow", 0);
+			if (stops_deferred)
+				sigdeferstop();
 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
-			if (error) {
+			if (error != 0 && gen == fip->fi_rgen) {
 				fip->fi_writers--;
 				if (fip->fi_writers == 0) {
-					socantrcvmore(fip->fi_readsock);
-					mtx_lock(&fifo_mtx);
-					fip->fi_wgen++;
-					mtx_unlock(&fifo_mtx);
+					PIPE_LOCK(fpipe);
+					fpipe->pipe_state |= PIPE_EOF;
+					if (fpipe->pipe_state & PIPE_WANTR)
+						wakeup(fpipe);
+					fpipe->pipe_wgen++;
+					PIPE_UNLOCK(fpipe);
 					fifo_cleanup(vp);
 				}
 				return (error);
@@ -307,85 +247,16 @@
 			 * a reader.  That (and not still having one)
 			 * is the condition that we must wait for.
 			 */
-			mtx_lock(&fifo_mtx);
+			PIPE_LOCK(fpipe);
 		}
 	}
-	mtx_unlock(&fifo_mtx);
+	PIPE_UNLOCK(fpipe);
 	KASSERT(fp != NULL, ("can't fifo/vnode bypass"));
 	KASSERT(fp->f_ops == &badfileops, ("not badfileops in fifo_open"));
-	finit(fp, fp->f_flag, DTYPE_FIFO, fip, &fifo_ops_f);
+	finit(fp, fp->f_flag, DTYPE_FIFO, fpipe, &pipeops);
 	return (0);
 }
 
-static void
-filt_fifordetach(struct knote *kn)
-{
-	struct socket *so = (struct socket *)kn->kn_hook;
-
-	SOCKBUF_LOCK(&so->so_rcv);
-	knlist_remove(&so->so_rcv.sb_sel.si_note, kn, 1);
-	if (knlist_empty(&so->so_rcv.sb_sel.si_note))
-		so->so_rcv.sb_flags &= ~SB_KNOTE;
-	SOCKBUF_UNLOCK(&so->so_rcv);
-}
-
-static int
-filt_fiforead(struct knote *kn, long hint)
-{
-	struct socket *so = (struct socket *)kn->kn_hook;
-
-	SOCKBUF_LOCK_ASSERT(&so->so_rcv);
-	kn->kn_data = so->so_rcv.sb_cc;
-	if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
-		kn->kn_flags |= EV_EOF;
-		return (1);
-	} else {
-		kn->kn_flags &= ~EV_EOF;
-		return (kn->kn_data > 0);
-	}
-}
-
-static void
-filt_fifowdetach(struct knote *kn)
-{
-	struct socket *so = (struct socket *)kn->kn_hook;
-
-	SOCKBUF_LOCK(&so->so_snd);
-	knlist_remove(&so->so_snd.sb_sel.si_note, kn, 1);
-	if (knlist_empty(&so->so_snd.sb_sel.si_note))
-		so->so_snd.sb_flags &= ~SB_KNOTE;
-	SOCKBUF_UNLOCK(&so->so_snd);
-}
-
-static int
-filt_fifowrite(struct knote *kn, long hint)
-{
-	struct socket *so = (struct socket *)kn->kn_hook;
-
-	SOCKBUF_LOCK_ASSERT(&so->so_snd);
-	kn->kn_data = sbspace(&so->so_snd);
-	if (so->so_snd.sb_state & SBS_CANTSENDMORE) {
-		kn->kn_flags |= EV_EOF;
-		return (1);
-	} else {
-		kn->kn_flags &= ~EV_EOF;
-	        return (kn->kn_data >= so->so_snd.sb_lowat);
-	}
-}
-
-static void
-filt_fifodetach_notsup(struct knote *kn)
-{
-
-}
-
-static int
-filt_fifo_notsup(struct knote *kn, long hint)
-{
-
-	return (0);
-}
-
 /*
  * Device close routine
  */
@@ -399,26 +270,39 @@
 		struct thread *a_td;
 	} */ *ap;
 {
-	struct vnode *vp = ap->a_vp;
-	struct fifoinfo *fip = vp->v_fifoinfo;
+	struct vnode *vp;
+	struct fifoinfo *fip;
+	struct pipe *cpipe;
 
+	vp = ap->a_vp;
+	fip = vp->v_fifoinfo;
+	cpipe = fip->fi_pipe;
 	ASSERT_VOP_ELOCKED(vp, "fifo_close");
-	if (fip == NULL) {
-		printf("fifo_close: no v_fifoinfo %p\n", vp);
-		return (0);
-	}
 	if (ap->a_fflag & FREAD) {
 		fip->fi_readers--;
-		if (fip->fi_readers == 0)
-			socantsendmore(fip->fi_writesock);
+		if (fip->fi_readers == 0) {
+			PIPE_LOCK(cpipe);
+			cpipe->pipe_state |= PIPE_EOF;
+			if ((cpipe->pipe_state & PIPE_WANTW)) {
+				cpipe->pipe_state &= ~PIPE_WANTW;
+				wakeup(cpipe);
+			}
+			pipeselwakeup(cpipe);
+			PIPE_UNLOCK(cpipe);
+		}
 	}
 	if (ap->a_fflag & FWRITE) {
 		fip->fi_writers--;
 		if (fip->fi_writers == 0) {
-			socantrcvmore(fip->fi_readsock);
-			mtx_lock(&fifo_mtx);
-			fip->fi_wgen++;
-			mtx_unlock(&fifo_mtx);
+			PIPE_LOCK(cpipe);
+			cpipe->pipe_state |= PIPE_EOF;
+			if ((cpipe->pipe_state & PIPE_WANTR)) {
+				cpipe->pipe_state &= ~PIPE_WANTR;
+				wakeup(cpipe);
+			}
+			cpipe->pipe_wgen++;
+			pipeselwakeup(cpipe);
+			PIPE_UNLOCK(cpipe);
 		}
 	}
 	fifo_cleanup(vp);
@@ -504,212 +388,3 @@
 	return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL);
 }
 
-static int
-fifo_close_f(struct file *fp, struct thread *td)
-{
-
-	return (vnops.fo_close(fp, td));
-}
-
-/*
- * The implementation of ioctl() for named fifos is complicated by the fact
- * that we permit O_RDWR fifo file descriptors, meaning that the actions of
- * ioctls may have to be applied to both the underlying sockets rather than
- * just one.  The original implementation simply forward the ioctl to one
- * or both sockets based on fp->f_flag.  We now consider each ioctl
- * separately, as the composition effect requires careful ordering.
- *
- * We do not blindly pass all ioctls through to the socket in order to avoid
- * providing unnecessary ioctls that might be improperly depended on by
- * applications (such as socket-specific, routing, and interface ioctls).
- *
- * Unlike sys_pipe.c, fifos do not implement the deprecated TIOCSPGRP and
- * TIOCGPGRP ioctls.  Earlier implementations of fifos did forward SIOCSPGRP
- * and SIOCGPGRP ioctls, so we might need to re-add those here.
- */
-static int
-fifo_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred,
-    struct thread *td)
-{
-	struct fifoinfo *fi;
-	struct file filetmp;	/* Local, so need not be locked. */
-	int error;
-
-	error = ENOTTY;
-	fi = fp->f_data;
-
-	switch (com) {
-	case FIONBIO:
-		/*
-		 * Non-blocking I/O is implemented at the fifo layer using
-		 * MSG_NBIO, so does not need to be forwarded down the stack.
-		 */
-		return (0);
-
-	case FIOASYNC:
-	case FIOSETOWN:
-	case FIOGETOWN:
-		/*
-		 * These socket ioctls don't have any ordering requirements,
-		 * so are called in an arbitrary order, and only on the
-		 * sockets indicated by the file descriptor rights.
-		 *
-		 * XXXRW: If O_RDWR and the read socket accepts an ioctl but
-		 * the write socket doesn't, the socketpair is left in an
-		 * inconsistent state.
-		 */
-		if (fp->f_flag & FREAD) {
-			filetmp.f_data = fi->fi_readsock;
-			filetmp.f_cred = cred;
-			error = soo_ioctl(&filetmp, com, data, cred, td);
-			if (error)
-				return (error);
-		}
-		if (fp->f_flag & FWRITE) {
-			filetmp.f_data = fi->fi_writesock;
-			filetmp.f_cred = cred;
-			error = soo_ioctl(&filetmp, com, data, cred, td);
-		}
-		return (error);
-
-	case FIONREAD:
-		/*
-		 * FIONREAD will return 0 for non-readable descriptors, and
-		 * the results of FIONREAD on the read socket for readable
-		 * descriptors.
-		 */
-		if (!(fp->f_flag & FREAD)) {
-			*(int *)data = 0;
-			return (0);
-		}
-		filetmp.f_data = fi->fi_readsock;
-		filetmp.f_cred = cred;
-		return (soo_ioctl(&filetmp, com, data, cred, td));
-
-	default:
-		return (ENOTTY);
-	}
-}
-
-/*
- * Because fifos are now a file descriptor layer object, EVFILT_VNODE is not
- * implemented.  Likely, fifo_kqfilter() should be removed, and
- * fifo_kqfilter_f() should know how to forward the request to the underling
- * vnode using f_vnode in the file descriptor here.
- */
-static int
-fifo_kqfilter_f(struct file *fp, struct knote *kn)
-{
-	struct fifoinfo *fi;
-	struct socket *so;
-	struct sockbuf *sb;
-
-	fi = fp->f_data;
-
-	/*
-	 * If a filter is requested that is not supported by this file
-	 * descriptor, don't return an error, but also don't ever generate an
-	 * event.
-	 */
-	if ((kn->kn_filter == EVFILT_READ) && !(fp->f_flag & FREAD)) {
-		kn->kn_fop = &fifo_notsup_filtops;
-		return (0);
-	}
-
-	if ((kn->kn_filter == EVFILT_WRITE) && !(fp->f_flag & FWRITE)) {
-		kn->kn_fop = &fifo_notsup_filtops;
-		return (0);
-	}
-
-	switch (kn->kn_filter) {
-	case EVFILT_READ:
-		kn->kn_fop = &fiforead_filtops;
-		so = fi->fi_readsock;
-		sb = &so->so_rcv;
-		break;
-	case EVFILT_WRITE:
-		kn->kn_fop = &fifowrite_filtops;
-		so = fi->fi_writesock;
-		sb = &so->so_snd;
-		break;
-	default:
-		return (EINVAL);
-	}
-
-	kn->kn_hook = (caddr_t)so;
-
-	SOCKBUF_LOCK(sb);
-	knlist_add(&sb->sb_sel.si_note, kn, 1);
-	sb->sb_flags |= SB_KNOTE;
-	SOCKBUF_UNLOCK(sb);
-
-	return (0);
-}
-
-static int
-fifo_poll_f(struct file *fp, int events, struct ucred *cred, struct thread *td)
-{
-	struct fifoinfo *fip;
-	struct file filetmp;
-	int levents, revents = 0;
-
-	fip = fp->f_data;
-	levents = events &
-	    (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | POLLRDBAND);
-	if ((fp->f_flag & FREAD) && levents) {
-		filetmp.f_data = fip->fi_readsock;
-		filetmp.f_cred = cred;
-		mtx_lock(&fifo_mtx);
-		if (fp->f_seqcount == fip->fi_wgen)
-			levents |= POLLINIGNEOF;
-		mtx_unlock(&fifo_mtx);
-		revents |= soo_poll(&filetmp, levents, cred, td);
-	}
-	levents = events & (POLLOUT | POLLWRNORM | POLLWRBAND);
-	if ((fp->f_flag & FWRITE) && levents) {
-		filetmp.f_data = fip->fi_writesock;
-		filetmp.f_cred = cred;
-		revents |= soo_poll(&filetmp, levents, cred, td);
-	}
-	return (revents);
-}
-
-static int
-fifo_read_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td)
-{
-	struct fifoinfo *fip;
-	int sflags;
-
-	fip = fp->f_data;
-	KASSERT(uio->uio_rw == UIO_READ,("fifo_read mode"));
-	if (uio->uio_resid == 0)
-		return (0);
-	sflags = (fp->f_flag & FNONBLOCK) ? MSG_NBIO : 0;
-	return (soreceive(fip->fi_readsock, NULL, uio, NULL, NULL, &sflags));
-}
-
-static int
-fifo_stat_f(struct file *fp, struct stat *sb, struct ucred *cred, struct thread *td)
-{
-
-	return (vnops.fo_stat(fp, sb, cred, td));
-}
-
-static int
-fifo_truncate_f(struct file *fp, off_t length, struct ucred *cred, struct thread *td)
-{
-
-	return (vnops.fo_truncate(fp, length, cred, td));
-}
-
-static int
-fifo_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td)
-{
-	struct fifoinfo *fip;
-	int sflags;
-
-	fip = fp->f_data;
-	KASSERT(uio->uio_rw == UIO_WRITE,("fifo_write mode"));
-	sflags = (fp->f_flag & FNONBLOCK) ? MSG_NBIO : 0;
-	return (sosend(fip->fi_writesock, NULL, uio, 0, NULL, sflags, td));
-}

Modified: trunk/sys/fs/msdosfs/bootsect.h
===================================================================
--- trunk/sys/fs/msdosfs/bootsect.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/bootsect.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,5 @@
 /* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/fs/msdosfs/bootsect.h 203827 2010-02-13 12:41:07Z kib $ */
 /*	$NetBSD: bootsect.h,v 1.9 1997/11/17 15:36:17 ws Exp $	*/
 
 /*-

Modified: trunk/sys/fs/msdosfs/bpb.h
===================================================================
--- trunk/sys/fs/msdosfs/bpb.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/bpb.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,5 @@
 /* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/fs/msdosfs/bpb.h 203827 2010-02-13 12:41:07Z kib $ */
 /*	$NetBSD: bpb.h,v 1.7 1997/11/17 15:36:24 ws Exp $	*/
 
 /*-

Modified: trunk/sys/fs/msdosfs/denode.h
===================================================================
--- trunk/sys/fs/msdosfs/denode.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/denode.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,5 @@
 /* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/fs/msdosfs/denode.h 234605 2012-04-23 13:21:28Z trasz $ */
 /*	$NetBSD: denode.h,v 1.25 1997/11/17 15:36:28 ws Exp $	*/
 
 /*-
@@ -276,6 +277,6 @@
 int createde(struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp);
 int deupdat(struct denode *dep, int waitfor);
 int removede(struct denode *pdep, struct denode *dep);
-int detrunc(struct denode *dep, u_long length, int flags, struct ucred *cred, struct thread *td);
+int detrunc(struct denode *dep, u_long length, int flags, struct ucred *cred);
 int doscheckpath( struct denode *source, struct denode *target);
 #endif	/* _KERNEL */

Modified: trunk/sys/fs/msdosfs/direntry.h
===================================================================
--- trunk/sys/fs/msdosfs/direntry.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/direntry.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,5 @@
 /* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/fs/msdosfs/direntry.h 298799 2016-04-29 20:19:41Z kp $ */
 /*	$NetBSD: direntry.h,v 1.14 1997/11/17 15:36:32 ws Exp $	*/
 
 /*-
@@ -145,7 +146,7 @@
 
 char	*mbnambuf_flush(struct mbnambuf *nbp, struct dirent *dp);
 void	mbnambuf_init(struct mbnambuf *nbp);
-void	mbnambuf_write(struct mbnambuf *nbp, char *name, int id);
+int	mbnambuf_write(struct mbnambuf *nbp, char *name, int id);
 int	dos2unixfn(u_char dn[11], u_char *un, int lower,
 	    struct msdosfsmount *pmp);
 int	unix2dosfn(const u_char *un, u_char dn[12], size_t unlen, u_int gen,

Modified: trunk/sys/fs/msdosfs/fat.h
===================================================================
--- trunk/sys/fs/msdosfs/fat.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/fat.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,5 @@
 /* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/fs/msdosfs/fat.h 139776 2005-01-06 18:10:42Z imp $ */
 /*	$NetBSD: fat.h,v 1.12 1997/11/17 15:36:36 ws Exp $	*/
 
 /*-

Modified: trunk/sys/fs/msdosfs/msdosfs_conv.c
===================================================================
--- trunk/sys/fs/msdosfs/msdosfs_conv.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/msdosfs_conv.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,5 @@
 /* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/fs/msdosfs/msdosfs_conv.c 333611 2018-05-14 19:21:57Z pfg $ */
 /*	$NetBSD: msdosfs_conv.c,v 1.25 1997/11/17 15:36:40 ws Exp $	*/
 
 /*-
@@ -257,7 +258,7 @@
 	 * Copy the name portion into the unix filename string.
 	 */
 	for (i = 8; i > 0 && *dn != ' ';) {
-		c = dos2unixchr(tmpbuf, (const u_char **)&dn, &i,
+		c = dos2unixchr(tmpbuf, __DECONST(const u_char **, &dn), &i,
 		    lower & LCASE_BASE, pmp);
 		while (*c != '\0') {
 			*un++ = *c++;
@@ -274,8 +275,8 @@
 		*un++ = '.';
 		thislong++;
 		for (i = 3; i > 0 && *dn != ' ';) {
-			c = dos2unixchr(tmpbuf, (const u_char **)&dn, &i,
-			    lower & LCASE_EXT, pmp);
+			c = dos2unixchr(tmpbuf, __DECONST(const u_char **, &dn),
+			    &i, lower & LCASE_EXT, pmp);
 			while (*c != '\0') {
 				*un++ = *c++;
 				thislong++;
@@ -581,7 +582,7 @@
 		if (!code)
 			end = WIN_LAST;
 	}
-	if (*un == '\0')
+	if (!unlen)
 		end = WIN_LAST;
 	wep->weCnt |= end;
 	return !end;
@@ -629,7 +630,8 @@
 		 * to look up or create files in case sensitive even when
 		 * it's a long file name.
 		 */
-		c1 = unix2winchr((const u_char **)&np, &len, LCASE_BASE, pmp);
+		c1 = unix2winchr(__DECONST(const u_char **, &np), &len,
+		    LCASE_BASE, pmp);
 		c2 = unix2winchr(&un, &unlen, LCASE_BASE, pmp);
 		if (c1 != c2)
 			return -2;
@@ -677,7 +679,9 @@
 		switch (code) {
 		case 0:
 			*np = '\0';
-			mbnambuf_write(nbp, name, (wep->weCnt & WIN_CNT) - 1);
+			if (mbnambuf_write(nbp, name,
+			    (wep->weCnt & WIN_CNT) - 1) != 0)
+				return -1;
 			return chksum;
 		case '/':
 			*np = '\0';
@@ -695,7 +699,9 @@
 		switch (code) {
 		case 0:
 			*np = '\0';
-			mbnambuf_write(nbp, name, (wep->weCnt & WIN_CNT) - 1);
+			if (mbnambuf_write(nbp, name,
+			    (wep->weCnt & WIN_CNT) - 1) != 0)
+				return -1;
 			return chksum;
 		case '/':
 			*np = '\0';
@@ -713,7 +719,9 @@
 		switch (code) {
 		case 0:
 			*np = '\0';
-			mbnambuf_write(nbp, name, (wep->weCnt & WIN_CNT) - 1);
+			if (mbnambuf_write(nbp, name,
+			    (wep->weCnt & WIN_CNT) - 1) != 0)
+				return -1;
 			return chksum;
 		case '/':
 			*np = '\0';
@@ -727,7 +735,8 @@
 		cp += 2;
 	}
 	*np = '\0';
-	mbnambuf_write(nbp, name, (wep->weCnt & WIN_CNT) - 1);
+	if (mbnambuf_write(nbp, name, (wep->weCnt & WIN_CNT) - 1) != 0)
+		return -1;
 	return chksum;
 }
 
@@ -774,7 +783,7 @@
 }
 
 /*
- * Determine the number of bytes neccesary for Win95 names
+ * Determine the number of bytes neccessary for Win95 names
  */
 size_t
 winLenFixup(un, unlen)
@@ -788,7 +797,7 @@
 }
 
 /*
- * Store an area with multi byte string instr, and reterns left
+ * Store an area with multi byte string instr, and returns left
  * byte of instr and moves pointer forward. The area's size is
  * inlen or outlen.
  */
@@ -947,8 +956,8 @@
 		ilen = 2;
 		olen = len = 4;
 		inp = inbuf;
-		msdosfs_iconv->convchr(pmp->pm_w2u, (const char **)&inp, &ilen,
-				     (char **)&outp, &olen);
+		msdosfs_iconv->convchr(pmp->pm_w2u, __DECONST(const char **,
+		    &inp), &ilen, (char **)&outp, &olen);
 		len -= olen;
 
 		/*
@@ -1029,7 +1038,7 @@
  * This only penalizes portions of substrings that contain more than
  * WIN_CHARS bytes when they are first encountered.
  */
-void
+int
 mbnambuf_write(struct mbnambuf *nbp, char *name, int id)
 {
 	char *slot;
@@ -1040,7 +1049,7 @@
 		printf("msdosfs: non-decreasing id: id %d, last id %d\n",
 		    id, nbp->nb_last_id);
 #endif
-		return;
+		return (EINVAL);
 	}
 
 	/* Will store this substring in a WIN_CHARS-aligned slot. */
@@ -1051,17 +1060,24 @@
 #ifdef MSDOSFS_DEBUG
 		printf("msdosfs: file name length %zu too large\n", newlen);
 #endif
-		return;
+		return (ENAMETOOLONG);
 	}
 
 	/* Shift suffix upwards by the amount length exceeds WIN_CHARS. */
-	if (count > WIN_CHARS && nbp->nb_len != 0)
+	if (count > WIN_CHARS && nbp->nb_len != 0) {
+		if ((id * WIN_CHARS + count + nbp->nb_len) >
+		    sizeof(nbp->nb_buf))
+			return (ENAMETOOLONG);
+
 		bcopy(slot + WIN_CHARS, slot + count, nbp->nb_len);
+	}
 
 	/* Copy in the substring to its slot and update length so far. */
 	bcopy(name, slot, count);
 	nbp->nb_len = newlen;
 	nbp->nb_last_id = id;
+
+	return (0);
 }
 
 /*

Modified: trunk/sys/fs/msdosfs/msdosfs_denode.c
===================================================================
--- trunk/sys/fs/msdosfs/msdosfs_denode.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/msdosfs_denode.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,5 @@
 /* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/fs/msdosfs/msdosfs_denode.c 254627 2013-08-21 23:04:48Z ken $ */
 /*	$NetBSD: msdosfs_denode.c,v 1.28 1998/02/10 14:10:00 mrg Exp $	*/
 
 /*-
@@ -142,12 +143,6 @@
 		KASSERT((*depp)->de_diroffset == diroffset, ("wrong diroffset"));
 		return (0);
 	}
-
-	/*
-	 * Do the malloc before the getnewvnode since doing so afterward
-	 * might cause a bogus v_data pointer to get dereferenced
-	 * elsewhere if malloc should block.
-	 */
 	ldep = malloc(sizeof(struct denode), M_MSDOSFSNODE, M_WAITOK | M_ZERO);
 
 	/*
@@ -310,8 +305,8 @@
 	if ((dep->de_flag & DE_MODIFIED) == 0 && waitfor == 0)
 		return (0);
 	dep->de_flag &= ~DE_MODIFIED;
-	if (dep->de_Attributes & ATTR_DIRECTORY)
-		return (0);
+	if (DETOV(dep)->v_vflag & VV_ROOT)
+		return (EINVAL);
 	if (dep->de_refcnt <= 0)
 		return (0);
 	error = readde(dep, &bp, &dirp);
@@ -340,12 +335,11 @@
  * Truncate the file described by dep to the length specified by length.
  */
 int
-detrunc(dep, length, flags, cred, td)
+detrunc(dep, length, flags, cred)
 	struct denode *dep;
 	u_long length;
 	int flags;
 	struct ucred *cred;
-	struct thread *td;
 {
 	int error;
 	int allerror;
@@ -440,7 +434,7 @@
 	dep->de_FileSize = length;
 	if (!isadir)
 		dep->de_flag |= DE_UPDATE | DE_MODIFIED;
-	allerror = vtruncbuf(DETOV(dep), cred, td, length, pmp->pm_bpcluster);
+	allerror = vtruncbuf(DETOV(dep), cred, length, pmp->pm_bpcluster);
 #ifdef MSDOSFS_DEBUG
 	if (allerror)
 		printf("detrunc(): vtruncbuf error %d\n", allerror);
@@ -518,7 +512,7 @@
 		error = extendfile(dep, count, NULL, NULL, DE_CLEAR);
 		if (error) {
 			/* truncate the added clusters away again */
-			(void) detrunc(dep, dep->de_FileSize, 0, cred, NULL);
+			(void) detrunc(dep, dep->de_FileSize, 0, cred);
 			return (error);
 		}
 	}
@@ -598,7 +592,6 @@
 {
 	struct vnode *vp = ap->a_vp;
 	struct denode *dep = VTODE(vp);
-	struct thread *td = ap->a_td;
 	int error = 0;
 
 #ifdef MSDOSFS_DEBUG
@@ -621,7 +614,7 @@
 	       dep, dep->de_refcnt, vp->v_mount->mnt_flag, MNT_RDONLY);
 #endif
 	if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
-		error = detrunc(dep, (u_long) 0, 0, NOCRED, td);
+		error = detrunc(dep, (u_long) 0, 0, NOCRED);
 		dep->de_flag |= DE_UPDATE;
 		dep->de_Name[0] = SLOT_DELETED;
 	}
@@ -637,6 +630,6 @@
 	       vrefcnt(vp), dep->de_Name[0]);
 #endif
 	if (dep->de_Name[0] == SLOT_DELETED || dep->de_Name[0] == SLOT_EMPTY)
-		vrecycle(vp, td);
+		vrecycle(vp);
 	return (error);
 }

Modified: trunk/sys/fs/msdosfs/msdosfs_fat.c
===================================================================
--- trunk/sys/fs/msdosfs/msdosfs_fat.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/msdosfs_fat.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,5 @@
 /* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/fs/msdosfs/msdosfs_fat.c 308551 2016-11-11 20:06:07Z kib $ */
 /*	$NetBSD: msdosfs_fat.c,v 1.28 1997/11/17 15:36:49 ws Exp $	*/
 
 /*-
@@ -60,6 +61,8 @@
 #include <fs/msdosfs/fat.h>
 #include <fs/msdosfs/msdosfsmount.h>
 
+#define	FULL_RUN	((u_int)0xffffffff)
+
 static int	chainalloc(struct msdosfsmount *pmp, u_long start,
 		    u_long count, u_long fillwith, u_long *retcluster,
 		    u_long *got);
@@ -399,6 +402,10 @@
 
 	MSDOSFS_ASSERT_MP_LOCKED(pmp);
 
+	KASSERT(cn <= pmp->pm_maxcluster, ("cn too large %lu %lu", cn,
+	    pmp->pm_maxcluster));
+	KASSERT((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0,
+	    ("usemap_alloc on ro msdosfs mount"));
 	KASSERT((pmp->pm_inusemap[cn / N_INUSEBITS] & (1 << (cn % N_INUSEBITS)))
 	    == 0, ("Allocating used sector %ld %ld %x", cn, cn % N_INUSEBITS,
 		(unsigned)pmp->pm_inusemap[cn / N_INUSEBITS]));
@@ -415,6 +422,11 @@
 {
 
 	MSDOSFS_ASSERT_MP_LOCKED(pmp);
+
+	KASSERT(cn <= pmp->pm_maxcluster, ("cn too large %lu %lu", cn,
+	    pmp->pm_maxcluster));
+	KASSERT((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0,
+	    ("usemap_free on ro msdosfs mount"));
 	pmp->pm_freeclustercount++;
 	pmp->pm_flags |= MSDOSFS_FSIMOD;
 	KASSERT((pmp->pm_inusemap[cn / N_INUSEBITS] & (1 << (cn % N_INUSEBITS)))
@@ -666,6 +678,8 @@
 
 	MSDOSFS_ASSERT_MP_LOCKED(pmp);
 
+	if (start > pmp->pm_maxcluster)
+		return (0);
 	max_idx = pmp->pm_maxcluster / N_INUSEBITS;
 	idx = start / N_INUSEBITS;
 	start %= N_INUSEBITS;
@@ -673,11 +687,18 @@
 	map &= ~((1 << start) - 1);
 	if (map) {
 		len = ffs(map) - 1 - start;
-		return (len > count ? count : len);
+		len = MIN(len, count);
+		if (start + len > pmp->pm_maxcluster)
+			len = pmp->pm_maxcluster - start + 1;
+		return (len);
 	}
 	len = N_INUSEBITS - start;
-	if (len >= count)
-		return (count);
+	if (len >= count) {
+		len = count;
+		if (start + len > pmp->pm_maxcluster)
+			len = pmp->pm_maxcluster - start + 1;
+		return (len);
+	}
 	while (++idx <= max_idx) {
 		if (len >= count)
 			break;
@@ -688,7 +709,10 @@
 		}
 		len += N_INUSEBITS;
 	}
-	return (len > count ? count : len);
+	len = MIN(len, count);
+	if (start + len > pmp->pm_maxcluster)
+		len = pmp->pm_maxcluster - start + 1;
+	return (len);
 }
 
 /*
@@ -715,6 +739,8 @@
 	u_long cl, n;
 
 	MSDOSFS_ASSERT_MP_LOCKED(pmp);
+	KASSERT((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0,
+	    ("chainalloc on ro msdosfs mount"));
 
 	for (cl = start, n = count; n-- > 0;)
 		usemap_alloc(pmp, cl++);
@@ -723,8 +749,11 @@
 		pmp->pm_nxtfree = CLUST_FIRST;
 	pmp->pm_flags |= MSDOSFS_FSIMOD;
 	error = fatchain(pmp, start, count, fillwith);
-	if (error != 0)
+	if (error != 0) {
+		for (cl = start, n = count; n-- > 0;)
+			usemap_free(pmp, cl++);
 		return (error);
+	}
 #ifdef MSDOSFS_DEBUG
 	printf("clusteralloc(): allocated cluster chain at %lu (%lu clusters)\n",
 	    start, count);
@@ -786,8 +815,8 @@
 		idx = cn / N_INUSEBITS;
 		map = pmp->pm_inusemap[idx];
 		map |= (1 << (cn % N_INUSEBITS)) - 1;
-		if (map != (u_int)-1) {
-			cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
+		if (map != FULL_RUN) {
+			cn = idx * N_INUSEBITS + ffs(map ^ FULL_RUN) - 1;
 			if ((l = chainlength(pmp, cn, count)) >= count)
 				return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
 			if (l > foundl) {
@@ -803,8 +832,8 @@
 		idx = cn / N_INUSEBITS;
 		map = pmp->pm_inusemap[idx];
 		map |= (1 << (cn % N_INUSEBITS)) - 1;
-		if (map != (u_int)-1) {
-			cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
+		if (map != FULL_RUN) {
+			cn = idx * N_INUSEBITS + ffs(map ^ FULL_RUN) - 1;
 			if ((l = chainlength(pmp, cn, count)) >= count)
 				return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
 			if (l > foundl) {
@@ -915,7 +944,7 @@
 	 * loop further down.
 	 */
 	for (cn = 0; cn < (pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS; cn++)
-		pmp->pm_inusemap[cn] = (u_int)-1;
+		pmp->pm_inusemap[cn] = FULL_RUN;
 
 	/*
 	 * Figure how many free clusters are in the filesystem by ripping
@@ -945,11 +974,16 @@
 			readcn >>= 4;
 		readcn &= pmp->pm_fatmask;
 
-		if (readcn == 0)
+		if (readcn == CLUST_FREE)
 			usemap_free(pmp, cn);
 	}
 	if (bp != NULL)
 		brelse(bp);
+
+	for (cn = pmp->pm_maxcluster + 1; cn < (pmp->pm_maxcluster +
+	    N_INUSEBITS) / N_INUSEBITS; cn++)
+		pmp->pm_inusemap[cn / N_INUSEBITS] |= 1 << (cn % N_INUSEBITS);
+
 	return (0);
 }
 
@@ -1013,12 +1047,14 @@
 	while (count > 0) {
 		/*
 		 * Allocate a new cluster chain and cat onto the end of the
-		 * file.  * If the file is empty we make de_StartCluster point
-		 * to the new block.  Note that de_StartCluster being 0 is
-		 * sufficient to be sure the file is empty since we exclude
-		 * attempts to extend the root directory above, and the root
-		 * dir is the only file with a startcluster of 0 that has
-		 * blocks allocated (sort of).
+		 * file.
+		 * If the file is empty we make de_StartCluster point
+		 * to the new block.  Note that de_StartCluster being
+		 * 0 is sufficient to be sure the file is empty since
+		 * we exclude attempts to extend the root directory
+		 * above, and the root dir is the only file with a
+		 * startcluster of 0 that has blocks allocated (sort
+		 * of).
 		 */
 		if (dep->de_StartCluster == 0)
 			cn = 0;

Modified: trunk/sys/fs/msdosfs/msdosfs_fileno.c
===================================================================
--- trunk/sys/fs/msdosfs/msdosfs_fileno.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/msdosfs_fileno.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003-2004 Tim J. Robbins.
  * All rights reserved.
@@ -43,7 +44,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/fs/msdosfs/msdosfs_fileno.c 263670 2014-03-23 19:48:30Z pfg $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -75,7 +76,7 @@
 
 	RB_INIT(&pmp->pm_filenos);
 	pmp->pm_nfileno = FILENO_FIRST_DYN;
-        if (pmp->pm_HugeSectors > 0xffffffff /
+	if (pmp->pm_HugeSectors > 0xffffffff /
 	    (pmp->pm_BytesPerSec / sizeof(struct direntry)) + 1)
 		pmp->pm_flags |= MSDOSFS_LARGEFS;
 }

Modified: trunk/sys/fs/msdosfs/msdosfs_iconv.c
===================================================================
--- trunk/sys/fs/msdosfs/msdosfs_iconv.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/msdosfs_iconv.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003 Ryuichiro Imura
  * All rights reserved.
@@ -25,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/sys/fs/msdosfs/msdosfs_iconv.c 171753 2007-08-07 02:25:56Z bde $");
 
 #include <sys/param.h>
 #include <sys/iconv.h>

Modified: trunk/sys/fs/msdosfs/msdosfs_lookup.c
===================================================================
--- trunk/sys/fs/msdosfs/msdosfs_lookup.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/msdosfs_lookup.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,5 @@
 /* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/fs/msdosfs/msdosfs_lookup.c 276500 2015-01-01 10:44:20Z kib $ */
 /*	$NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws Exp $	*/
 
 /*-
@@ -63,8 +64,6 @@
 
 static int msdosfs_lookup_(struct vnode *vdp, struct vnode **vpp,
     struct componentname *cnp, u_int64_t *inum);
-static int msdosfs_deget_dotdot(struct vnode *vp, u_long cluster, int blkoff,
-    struct vnode **rvp);
 
 int
 msdosfs_lookup(struct vop_cachedlookup_args *ap)
@@ -73,6 +72,28 @@
 	return (msdosfs_lookup_(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL));
 }
 
+struct deget_dotdot {
+	u_long cluster;
+	int blkoff;
+};
+
+static int
+msdosfs_deget_dotdot(struct mount *mp, void *arg, int lkflags,
+    struct vnode **rvp)
+{
+	struct deget_dotdot *dd_arg;
+	struct denode *rdp;
+	struct msdosfsmount *pmp;
+	int error;
+
+	pmp = VFSTOMSDOSFS(mp);
+	dd_arg = arg;
+	error = deget(pmp, dd_arg->cluster, dd_arg->blkoff,  &rdp);
+	if (error == 0)
+		*rvp = DETOV(rdp);
+	return (error);
+}
+
 /*
  * When we search a directory the blocks containing directory entries are
  * read and examined.  The directory entries contain information that would
@@ -108,8 +129,9 @@
 	struct denode *dp;
 	struct denode *tdp;
 	struct msdosfsmount *pmp;
-	struct buf *bp = 0;
+	struct buf *bp = NULL;
 	struct direntry *dep = NULL;
+	struct deget_dotdot dd_arg;
 	u_char dosfilename[12];
 	int flags = cnp->cn_flags;
 	int nameiop = cnp->cn_nameiop;
@@ -395,7 +417,7 @@
 	 * and 8.3 filenames.  Hence, it may not invalidate all negative
 	 * entries if a file with this name is later created.
 	 */
-	if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
+	if ((cnp->cn_flags & MAKEENTRY) != 0)
 		cache_enter(vdp, *vpp, cnp);
 #endif
 	return (ENOENT);
@@ -524,8 +546,11 @@
 	 */
 	pdp = vdp;
 	if (flags & ISDOTDOT) {
-		error = msdosfs_deget_dotdot(pdp, cluster, blkoff, vpp);
-		if (error) {
+		dd_arg.cluster = cluster;
+		dd_arg.blkoff = blkoff;
+		error = vn_vget_ino_gen(vdp, msdosfs_deget_dotdot,
+		    &dd_arg, cnp->cn_lkflags, vpp);
+		if (error != 0) {
 			*vpp = NULL;
 			return (error);
 		}
@@ -560,54 +585,6 @@
 	return (0);
 }
 
-static int
-msdosfs_deget_dotdot(struct vnode *vp, u_long cluster, int blkoff,
-    struct vnode **rvp)
-{
-	struct mount *mp;
-	struct msdosfsmount *pmp;
-	struct denode *rdp;
-	int ltype, error;
-
-	mp = vp->v_mount;
-	pmp = VFSTOMSDOSFS(mp);
-	ltype = VOP_ISLOCKED(vp);
-	KASSERT(ltype == LK_EXCLUSIVE || ltype == LK_SHARED,
-	    ("msdosfs_deget_dotdot: vp not locked"));
-
-	error = vfs_busy(mp, MBF_NOWAIT);
-	if (error != 0) {
-		vfs_ref(mp);
-		VOP_UNLOCK(vp, 0);
-		error = vfs_busy(mp, 0);
-		vn_lock(vp, ltype | LK_RETRY);
-		vfs_rel(mp);
-		if (error != 0)
-			return (ENOENT);
-		if (vp->v_iflag & VI_DOOMED) {
-			vfs_unbusy(mp);
-			return (ENOENT);
-		}
-	}
-	VOP_UNLOCK(vp, 0);
-	error = deget(pmp, cluster, blkoff,  &rdp);
-	vfs_unbusy(mp);
-	if (error == 0)
-		*rvp = DETOV(rdp);
-	if (*rvp != vp)
-		vn_lock(vp, ltype | LK_RETRY);
-	if (vp->v_iflag & VI_DOOMED) {
-		if (error == 0) {
-			if (*rvp == vp)
-				vunref(*rvp);
-			else
-				vput(*rvp);
-		}
-		error = ENOENT;
-	}
-	return (error);
-}
-
 /*
  * dep  - directory entry to copy into the directory
  * ddep - directory to add to
@@ -649,7 +626,7 @@
 		dirclust = de_clcount(pmp, diroffset);
 		error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR);
 		if (error) {
-			(void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED, NULL);
+			(void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED);
 			return error;
 		}
 

Modified: trunk/sys/fs/msdosfs/msdosfs_vfsops.c
===================================================================
--- trunk/sys/fs/msdosfs/msdosfs_vfsops.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/msdosfs_vfsops.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,5 @@
 /* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/fs/msdosfs/msdosfs_vfsops.c 308552 2016-11-11 20:08:45Z kib $ */
 /*	$NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $	*/
 
 /*-
@@ -175,24 +176,8 @@
 
 	if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
 		pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
-	else if (!(pmp->pm_flags &
-	    (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) {
-		struct vnode *rootvp;
-
-		/*
-		 * Try to divine whether to support Win'95 long filenames
-		 */
-		if (FAT32(pmp))
-			pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
-		else {
-			if ((error =
-			    msdosfs_root(mp, LK_EXCLUSIVE, &rootvp)) != 0)
-				return error;
-			pmp->pm_flags |= findwin95(VTODE(rootvp)) ?
-			    MSDOSFSMNT_LONGNAME : MSDOSFSMNT_SHORTNAME;
-			vput(rootvp);
-		}
-	}
+	else
+		pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
 	return 0;
 }
 
@@ -759,7 +744,7 @@
 	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
 	MNT_ILOCK(mp);
 	mp->mnt_flag |= MNT_LOCAL;
-	mp->mnt_kern_flag |= MNTK_MPSAFE;
+	mp->mnt_kern_flag |= MNTK_USES_BCACHE | MNTK_NO_IOPF;
 	MNT_IUNLOCK(mp);
 
 	if (pmp->pm_flags & MSDOSFS_LARGEFS)
@@ -779,8 +764,7 @@
 	}
 	if (pmp) {
 		lockdestroy(&pmp->pm_fatlock);
-		if (pmp->pm_inusemap)
-			free(pmp->pm_inusemap, M_MSDOSFSFAT);
+		free(pmp->pm_inusemap, M_MSDOSFSFAT);
 		free(pmp, M_MSDOSFSMNT);
 		mp->mnt_data = NULL;
 	}
@@ -797,13 +781,17 @@
 	struct msdosfsmount *pmp;
 	int error, flags;
 
-	flags = 0;
-	if (mntflags & MNT_FORCE)
+	error = flags = 0;
+	pmp = VFSTOMSDOSFS(mp);
+	if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0)
+		error = msdosfs_sync(mp, MNT_WAIT);
+	if ((mntflags & MNT_FORCE) != 0)
 		flags |= FORCECLOSE;
+	else if (error != 0)
+		return (error);
 	error = vflush(mp, 0, flags, curthread);
-	if (error && error != ENXIO)
-		return error;
-	pmp = VFSTOMSDOSFS(mp);
+	if (error != 0 && error != ENXIO)
+		return (error);
 	if ((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0) {
 		error = markvoldirty(pmp, 0);
 		if (error && error != ENXIO) {

Modified: trunk/sys/fs/msdosfs/msdosfs_vnops.c
===================================================================
--- trunk/sys/fs/msdosfs/msdosfs_vnops.c	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/msdosfs_vnops.c	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,5 @@
 /* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/fs/msdosfs/msdosfs_vnops.c 308552 2016-11-11 20:08:45Z kib $ */
 /*	$NetBSD: msdosfs_vnops.c,v 1.68 1998/02/10 14:10:04 mrg Exp $	*/
 
 /*-
@@ -172,8 +173,7 @@
 	if (error)
 		goto bad;
 
-	ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ?
-				ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
+	ndirent.de_Attributes = ATTR_ARCHIVE;
 	ndirent.de_LowerCase = 0;
 	ndirent.de_StartCluster = 0;
 	ndirent.de_FileSize = 0;
@@ -185,6 +185,8 @@
 	if (error)
 		goto bad;
 	*ap->a_vpp = DETOV(dep);
+	if ((cnp->cn_flags & MAKEENTRY) != 0)
+		cache_enter(ap->a_dvp, *ap->a_vpp, cnp);
 	return (0);
 
 bad:
@@ -256,8 +258,7 @@
 	mode_t file_mode;
 	accmode_t accmode = ap->a_accmode;
 
-	file_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) |
-	    ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH));
+	file_mode = S_IRWXU|S_IRWXG|S_IRWXO;
 	file_mode &= (vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask);
 
 	/*
@@ -266,8 +267,8 @@
 	 */
 	if (accmode & VWRITE) {
 		switch (vp->v_type) {
+		case VREG:
 		case VDIR:
-		case VREG:
 			if (vp->v_mount->mnt_flag & MNT_RDONLY)
 				return (EROFS);
 			break;
@@ -322,10 +323,7 @@
 	else
 		vap->va_fileid = (long)fileid;
 
-	if ((dep->de_Attributes & ATTR_READONLY) == 0)
-		mode = S_IRWXU|S_IRWXG|S_IRWXO;
-	else
-		mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
+	mode = S_IRWXU|S_IRWXG|S_IRWXO;
 	vap->va_mode = mode & 
 	    (ap->a_vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask);
 	vap->va_uid = pmp->pm_uid;
@@ -345,8 +343,14 @@
 		vap->va_birthtime.tv_nsec = 0;
 	}
 	vap->va_flags = 0;
-	if ((dep->de_Attributes & ATTR_ARCHIVE) == 0)
-		vap->va_flags |= SF_ARCHIVED;
+	if (dep->de_Attributes & ATTR_ARCHIVE)
+		vap->va_flags |= UF_ARCHIVE;
+	if (dep->de_Attributes & ATTR_HIDDEN)
+		vap->va_flags |= UF_HIDDEN;
+	if (dep->de_Attributes & ATTR_READONLY)
+		vap->va_flags |= UF_READONLY;
+	if (dep->de_Attributes & ATTR_SYSTEM)
+		vap->va_flags |= UF_SYSTEM;
 	vap->va_gen = 0;
 	vap->va_blocksize = pmp->pm_bpcluster;
 	vap->va_bytes =
@@ -395,6 +399,18 @@
 #endif
 		return (EINVAL);
 	}
+
+	/*
+	 * We don't allow setting attributes on the root directory.
+	 * The special case for the root directory is because before
+	 * FAT32, the root directory didn't have an entry for itself
+	 * (and was otherwise special).  With FAT32, the root
+	 * directory is not so special, but still doesn't have an
+	 * entry for itself.
+	 */
+	if (vp->v_vflag & VV_ROOT)
+		return (EINVAL);
+
 	if (vap->va_flags != VNOVAL) {
 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
 			return (EROFS);
@@ -408,24 +424,29 @@
 		 * attributes.  We ignored the access time and the
 		 * read and execute bits.  We were strict for the other
 		 * attributes.
-		 *
-		 * Here we are strict, stricter than ufs in not allowing
-		 * users to attempt to set SF_SETTABLE bits or anyone to
-		 * set unsupported bits.  However, we ignore attempts to
-		 * set ATTR_ARCHIVE for directories `cp -pr' from a more
-		 * sensible filesystem attempts it a lot.
 		 */
-		if (vap->va_flags & SF_SETTABLE) {
-			error = priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0);
-			if (error)
-				return (error);
-		}
-		if (vap->va_flags & ~SF_ARCHIVED)
+		if (vap->va_flags & ~(UF_ARCHIVE | UF_HIDDEN | UF_READONLY |
+		    UF_SYSTEM))
 			return EOPNOTSUPP;
-		if (vap->va_flags & SF_ARCHIVED)
+		if (vap->va_flags & UF_ARCHIVE)
+			dep->de_Attributes |= ATTR_ARCHIVE;
+		else
 			dep->de_Attributes &= ~ATTR_ARCHIVE;
-		else if (!(dep->de_Attributes & ATTR_DIRECTORY))
-			dep->de_Attributes |= ATTR_ARCHIVE;
+		if (vap->va_flags & UF_HIDDEN)
+			dep->de_Attributes |= ATTR_HIDDEN;
+		else
+			dep->de_Attributes &= ~ATTR_HIDDEN;
+		/* We don't allow changing the readonly bit on directories. */
+		if (vp->v_type != VDIR) {
+			if (vap->va_flags & UF_READONLY)
+				dep->de_Attributes |= ATTR_READONLY;
+			else
+				dep->de_Attributes &= ~ATTR_READONLY;
+		}
+		if (vap->va_flags & UF_SYSTEM)
+			dep->de_Attributes |= ATTR_SYSTEM;
+		else
+			dep->de_Attributes &= ~ATTR_SYSTEM;
 		dep->de_flag |= DE_MODIFIED;
 	}
 
@@ -476,7 +497,7 @@
 			 */
 			break;
 		}
-		error = detrunc(dep, vap->va_size, 0, cred, td);
+		error = detrunc(dep, vap->va_size, 0, cred);
 		if (error)
 			return error;
 	}
@@ -483,27 +504,27 @@
 	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
 			return (EROFS);
-		if (vap->va_vaflags & VA_UTIMES_NULL) {
-			error = VOP_ACCESS(vp, VADMIN, cred, td); 
-			if (error)
-				error = VOP_ACCESS(vp, VWRITE, cred, td);
-		} else
-			error = VOP_ACCESS(vp, VADMIN, cred, td);
-		if (vp->v_type != VDIR) {
-			if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 &&
-			    vap->va_atime.tv_sec != VNOVAL) {
-				dep->de_flag &= ~DE_ACCESS;
-				timespec2fattime(&vap->va_atime, 0,
-				    &dep->de_ADate, NULL, NULL);
-			}
-			if (vap->va_mtime.tv_sec != VNOVAL) {
-				dep->de_flag &= ~DE_UPDATE;
-				timespec2fattime(&vap->va_mtime, 0,
-				    &dep->de_MDate, &dep->de_MTime, NULL);
-			}
+		error = vn_utimes_perm(vp, vap, cred, td);
+		if (error != 0)
+			return (error);
+		if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 &&
+		    vap->va_atime.tv_sec != VNOVAL) {
+			dep->de_flag &= ~DE_ACCESS;
+			timespec2fattime(&vap->va_atime, 0,
+			    &dep->de_ADate, NULL, NULL);
+		}
+		if (vap->va_mtime.tv_sec != VNOVAL) {
+			dep->de_flag &= ~DE_UPDATE;
+			timespec2fattime(&vap->va_mtime, 0,
+			    &dep->de_MDate, &dep->de_MTime, NULL);
+		}
+		/*
+		 * We don't set the archive bit when modifying the time of
+		 * a directory to emulate the Windows/DOS behavior.
+		 */
+		if (vp->v_type != VDIR)
 			dep->de_Attributes |= ATTR_ARCHIVE;
-			dep->de_flag |= DE_MODIFIED;
-		}
+		dep->de_flag |= DE_MODIFIED;
 	}
 	/*
 	 * DOS files only have the ability to have their writability
@@ -600,7 +621,7 @@
 			error = bread(vp, lbn, blsize, NOCRED, &bp);
 		} else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
 			error = cluster_read(vp, dep->de_FileSize, lbn, blsize,
-			    NOCRED, on + uio->uio_resid, seqcount, &bp);
+			    NOCRED, on + uio->uio_resid, seqcount, 0, &bp);
 		} else if (seqcount > 1) {
 			rasize = blsize;
 			error = breadn(vp, lbn,
@@ -620,11 +641,11 @@
 		diff = blsize - bp->b_resid;
 		if (diff < n)
 			n = diff;
-		error = uiomove(bp->b_data + on, (int) n, uio);
+		error = vn_io_fault_uiomove(bp->b_data + on, (int) n, uio);
 		brelse(bp);
 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
 	if (!isadir && (error == 0 || uio->uio_resid != orig_resid) &&
-	    (vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
+	    (vp->v_mount->mnt_flag & (MNT_NOATIME | MNT_RDONLY)) == 0)
 		dep->de_flag |= DE_ACCESS;
 	return (error);
 }
@@ -756,6 +777,12 @@
 			 * then no need to read data from disk.
 			 */
 			bp = getblk(thisvp, bn, pmp->pm_bpcluster, 0, 0, 0);
+			/*
+			 * This call to vfs_bio_clrbuf() ensures that
+			 * even if vn_io_fault_uiomove() below faults,
+			 * garbage from the newly instantiated buffer
+			 * is not exposed to the userspace via mmap().
+			 */
 			vfs_bio_clrbuf(bp);
 			/*
 			 * Do the bmap now, since pcbmap needs buffers
@@ -793,7 +820,7 @@
 		/*
 		 * Copy the data from user space into the buf header.
 		 */
-		error = uiomove(bp->b_data + croffset, n, uio);
+		error = vn_io_fault_uiomove(bp->b_data + croffset, n, uio);
 		if (error) {
 			brelse(bp);
 			break;
@@ -820,7 +847,7 @@
 		else if (n + croffset == pmp->pm_bpcluster) {
 			if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0)
 				cluster_write(vp, bp, dep->de_FileSize,
-				    seqcount);
+				    seqcount, 0);
 			else
 				bawrite(bp);
 		} else
@@ -835,11 +862,11 @@
 errexit:
 	if (error) {
 		if (ioflag & IO_UNIT) {
-			detrunc(dep, osize, ioflag & IO_SYNC, NOCRED, NULL);
+			detrunc(dep, osize, ioflag & IO_SYNC, NOCRED);
 			uio->uio_offset -= resid - uio->uio_resid;
 			uio->uio_resid = resid;
 		} else {
-			detrunc(dep, dep->de_FileSize, ioflag & IO_SYNC, NOCRED, NULL);
+			detrunc(dep, dep->de_FileSize, ioflag & IO_SYNC, NOCRED);
 			if (uio->uio_resid != resid)
 				error = 0;
 		}
@@ -1219,6 +1246,17 @@
 			VOP_UNLOCK(fvp, 0);
 			goto bad;
 		}
+		/*
+		 * If ip is for a directory, then its name should always
+		 * be "." since it is for the directory entry in the
+		 * directory itself (msdosfs_lookup() always translates
+		 * to the "." entry so as to get a unique denode, except
+		 * for the root directory there are different
+		 * complications).  However, we just corrupted its name
+		 * to pass the correct name to createde().  Undo this.
+		 */
+		if ((ip->de_Attributes & ATTR_DIRECTORY) != 0)
+			bcopy(oldname, ip->de_Name, 11);
 		ip->de_refcnt++;
 		zp->de_fndoffset = from_diroffset;
 		error = removede(zp, ip);
@@ -1460,7 +1498,6 @@
 	struct vnode *dvp = ap->a_dvp;
 	struct componentname *cnp = ap->a_cnp;
 	struct denode *ip, *dp;
-	struct thread *td = cnp->cn_thread;
 	int error;
 
 	ip = VTODE(vp);
@@ -1498,7 +1535,7 @@
 	/*
 	 * Truncate the directory that is being deleted.
 	 */
-	error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred, td);
+	error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred);
 	cache_purge(vp);
 
 out:

Modified: trunk/sys/fs/msdosfs/msdosfsmount.h
===================================================================
--- trunk/sys/fs/msdosfs/msdosfsmount.h	2018-05-27 22:18:36 UTC (rev 10027)
+++ trunk/sys/fs/msdosfs/msdosfsmount.h	2018-05-27 22:19:26 UTC (rev 10028)
@@ -1,4 +1,5 @@
 /* $MidnightBSD$ */
+/* $FreeBSD: stable/10/sys/fs/msdosfs/msdosfsmount.h 281095 2015-04-05 01:03:11Z kib $ */
 /*	$NetBSD: msdosfsmount.h,v 1.17 1997/11/17 15:37:07 ws Exp $	*/
 
 /*-
@@ -239,8 +240,8 @@
 	gid_t	gid;		/* gid that owns msdosfs files */
 	mode_t	mask;		/* file mask to be applied for msdosfs perms */
 	int	flags;		/* see below */
-	int magic;		/* version number */
-	u_int16_t u2w[128];     /* Local->Unicode table */
+	int	unused1;	/* unused, was version number */
+	u_int16_t unused2[128];	/* no longer used, was Local->Unicode table */
 	char	*cs_win;	/* Windows(Unicode) Charset */
 	char	*cs_dos;	/* DOS Charset */
 	char	*cs_local;	/* Local Charset */
@@ -264,6 +265,4 @@
 #define	MSDOSFS_LARGEFS		0x10000000	/* perform fileno mapping */
 #define	MSDOSFS_FSIMOD		0x01000000
 
-#define MSDOSFS_ARGSMAGIC	0xe4eff300
-
 #endif /* !_MSDOSFS_MSDOSFSMOUNT_H_ */



More information about the Midnightbsd-cvs mailing list