diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index 8fc9c5a86a75..e76b2f88b5d3 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -38,7 +38,7 @@
 #   xargs -n1 | sort | uniq -d;
 # done
 
-# 20141128: new clang import which bumps version from 3.4.1 to 3.5.0.
+# 20141201: new clang import which bumps version from 3.4.1 to 3.5.0.
 OLD_FILES+=usr/include/clang/3.4.1/__wmmintrin_aes.h
 OLD_FILES+=usr/include/clang/3.4.1/__wmmintrin_pclmul.h
 OLD_FILES+=usr/include/clang/3.4.1/altivec.h
@@ -74,6 +74,8 @@ OLD_FILES+=usr/include/clang/3.4.1/x86intrin.h
 OLD_FILES+=usr/include/clang/3.4.1/xmmintrin.h
 OLD_FILES+=usr/include/clang/3.4.1/xopintrin.h
 OLD_DIRS+=usr/include/clang/3.4.1
+# 20141129: mrouted rc.d scripts removed from base
+OLD_FILES+=etc/rc.d/mrouted
 # 20141126: convert sbin/mdconfig/tests to ATF format tests
 OLD_FILES+=usr/tests/sbin/mdconfig/legacy_test
 OLD_FILES+=usr/tests/sbin/mdconfig/mdconfig.test
diff --git a/bin/sh/eval.c b/bin/sh/eval.c
index c1a9cdbfcd93..d0460a024e3d 100644
--- a/bin/sh/eval.c
+++ b/bin/sh/eval.c
@@ -774,15 +774,7 @@ xtracecommand(struct arglist *varlist, struct arglist *arglist)
 	for (sp = arglist->list ; sp ; sp = sp->next) {
 		if (sep != 0)
 			out2c(' ');
-		/* Disambiguate command looking like assignment. */
-		if (sp == arglist->list &&
-				strchr(sp->text, '=') != NULL &&
-				strchr(sp->text, '\'') == NULL) {
-			out2c('\'');
-			out2str(sp->text);
-			out2c('\'');
-		} else
-			out2qstr(sp->text);
+		out2qstr(sp->text);
 		sep = ' ';
 	}
 	out2c('\n');
diff --git a/bin/sh/output.c b/bin/sh/output.c
index bf8e17d97ece..c6d118f11535 100644
--- a/bin/sh/output.c
+++ b/bin/sh/output.c
@@ -122,8 +122,7 @@ outqstr(const char *p, struct output *file)
 		outstr("''", file);
 		return;
 	}
-	/* Caller will handle '=' if necessary */
-	if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' ||
+	if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#=")] == '\0' ||
 			strcmp(p, "[") == 0) {
 		outstr(p, file);
 		return;
diff --git a/contrib/binutils/bfd/elf32-arm.c b/contrib/binutils/bfd/elf32-arm.c
index 83acfe564714..47b6566c2e2b 100644
--- a/contrib/binutils/bfd/elf32-arm.c
+++ b/contrib/binutils/bfd/elf32-arm.c
@@ -4960,7 +4960,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 		       + input_section->output_offset
 		       + rel->r_offset);
 
-        value = abs (relocation);
+        value = llabs (relocation);
 
         if (value >= 0x1000)
           return bfd_reloc_overflow;
@@ -4998,7 +4998,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 		       + input_section->output_offset
 		       + rel->r_offset);
 
-        value = abs (relocation);
+        value = llabs (relocation);
 
         if (value >= 0x1000)
           return bfd_reloc_overflow;
@@ -5984,7 +5984,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
         /* Calculate the value of the relevant G_n, in encoded
            constant-with-rotation format.  */
-        g_n = calculate_group_reloc_mask (abs (signed_value), group,
+        g_n = calculate_group_reloc_mask (llabs (signed_value), group,
                                           &residual);
 
         /* Check for overflow if required.  */
@@ -5998,7 +5998,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
             (*_bfd_error_handler)
               (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
               input_bfd, input_section,
-              (long) rel->r_offset, abs (signed_value), howto->name);
+              (long) rel->r_offset, llabs (signed_value), howto->name);
             return bfd_reloc_overflow;
           }
 
@@ -6077,7 +6077,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
         /* Calculate the value of the relevant G_{n-1} to obtain
            the residual at that stage.  */
-        calculate_group_reloc_mask (abs (signed_value), group - 1, &residual);
+        calculate_group_reloc_mask (llabs (signed_value), group - 1, &residual);
 
         /* Check for overflow.  */
         if (residual >= 0x1000)
@@ -6085,7 +6085,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
             (*_bfd_error_handler)
               (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
               input_bfd, input_section,
-              (long) rel->r_offset, abs (signed_value), howto->name);
+              (long) rel->r_offset, llabs (signed_value), howto->name);
             return bfd_reloc_overflow;
           }
 
@@ -6160,7 +6160,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
         /* Calculate the value of the relevant G_{n-1} to obtain
            the residual at that stage.  */
-        calculate_group_reloc_mask (abs (signed_value), group - 1, &residual);
+        calculate_group_reloc_mask (llabs (signed_value), group - 1, &residual);
 
         /* Check for overflow.  */
         if (residual >= 0x100)
@@ -6168,7 +6168,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
             (*_bfd_error_handler)
               (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
               input_bfd, input_section,
-              (long) rel->r_offset, abs (signed_value), howto->name);
+              (long) rel->r_offset, llabs (signed_value), howto->name);
             return bfd_reloc_overflow;
           }
 
@@ -6243,7 +6243,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
 
         /* Calculate the value of the relevant G_{n-1} to obtain
            the residual at that stage.  */
-        calculate_group_reloc_mask (abs (signed_value), group - 1, &residual);
+        calculate_group_reloc_mask (llabs (signed_value), group - 1, &residual);
 
         /* Check for overflow.  (The absolute value to go in the place must be
            divisible by four and, after having been divided by four, must
@@ -6253,7 +6253,7 @@ elf32_arm_final_link_relocate (reloc_howto_type *           howto,
             (*_bfd_error_handler)
               (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
               input_bfd, input_section,
-              (long) rel->r_offset, abs (signed_value), howto->name);
+              (long) rel->r_offset, llabs (signed_value), howto->name);
             return bfd_reloc_overflow;
           }
 
diff --git a/contrib/gcc/config/arm/lib1funcs.asm b/contrib/gcc/config/arm/lib1funcs.asm
index 9245b3ca0c0d..c29f89496cf2 100644
--- a/contrib/gcc/config/arm/lib1funcs.asm
+++ b/contrib/gcc/config/arm/lib1funcs.asm
@@ -980,8 +980,6 @@ LSYM(Lover12):
 
 	RET
 
-	FUNC_END aeabi_ldiv0
-	FUNC_END aeabi_idiv0
 	FUNC_END div0
 	
 #endif /* L_divmodsi_tools */
diff --git a/contrib/ofed/librdmacm/examples/build/cmatose/Makefile b/contrib/ofed/librdmacm/examples/build/cmatose/Makefile
index c4515ac33ebc..31d2ae7f7f6b 100644
--- a/contrib/ofed/librdmacm/examples/build/cmatose/Makefile
+++ b/contrib/ofed/librdmacm/examples/build/cmatose/Makefile
@@ -6,5 +6,6 @@ PROG=	cmatose
 MAN=
 SRCS=	cmatose.c
 LDADD+= -libverbs -lrdmacm -lpthread
+LDADD+= -lmlx4
 
 .include <bsd.prog.mk>
diff --git a/contrib/ofed/librdmacm/examples/build/mckey/Makefile b/contrib/ofed/librdmacm/examples/build/mckey/Makefile
index d4ad2954d52b..4abaf2786d56 100644
--- a/contrib/ofed/librdmacm/examples/build/mckey/Makefile
+++ b/contrib/ofed/librdmacm/examples/build/mckey/Makefile
@@ -6,5 +6,6 @@ PROG=	mckey
 MAN=
 SRCS=	mckey.c
 LDADD+= -libverbs -lrdmacm -lpthread
+LDADD+= -lmlx4
 
 .include <bsd.prog.mk>
diff --git a/contrib/ofed/librdmacm/examples/build/rping/Makefile b/contrib/ofed/librdmacm/examples/build/rping/Makefile
index 05ef562400e9..b167a543c092 100644
--- a/contrib/ofed/librdmacm/examples/build/rping/Makefile
+++ b/contrib/ofed/librdmacm/examples/build/rping/Makefile
@@ -6,5 +6,6 @@ PROG=	rping
 MAN=
 SRCS=	rping.c
 LDADD+= -libverbs -lrdmacm -lpthread
+LDADD+= -lmlx4
 
 .include <bsd.prog.mk>
diff --git a/contrib/ofed/librdmacm/examples/build/udaddy/Makefile b/contrib/ofed/librdmacm/examples/build/udaddy/Makefile
index 16d941974b65..1e325505bc86 100644
--- a/contrib/ofed/librdmacm/examples/build/udaddy/Makefile
+++ b/contrib/ofed/librdmacm/examples/build/udaddy/Makefile
@@ -6,5 +6,6 @@ PROG=	udaddy
 MAN=
 SRCS=	udaddy.c
 LDADD+= -libverbs -lrdmacm -lpthread
+LDADD+= -lmlx4
 
 .include <bsd.prog.mk>
diff --git a/contrib/ofed/management/infiniband-diags/src/ibnetdiscover.c b/contrib/ofed/management/infiniband-diags/src/ibnetdiscover.c
index 2cfaa8ae55ef..5e092f7b0877 100644
--- a/contrib/ofed/management/infiniband-diags/src/ibnetdiscover.c
+++ b/contrib/ofed/management/infiniband-diags/src/ibnetdiscover.c
@@ -50,7 +50,7 @@
 #include <infiniband/common.h>
 #include <infiniband/umad.h>
 #include <infiniband/mad.h>
-#include <infiniband/complib/cl_nodenamemap.h>
+#include <complib/cl_nodenamemap.h>
 
 #include "ibnetdiscover.h"
 #include "grouping.h"
diff --git a/contrib/ofed/management/infiniband-diags/src/ibroute.c b/contrib/ofed/management/infiniband-diags/src/ibroute.c
index f2ee170cedc0..9607aa9999a5 100644
--- a/contrib/ofed/management/infiniband-diags/src/ibroute.c
+++ b/contrib/ofed/management/infiniband-diags/src/ibroute.c
@@ -49,7 +49,7 @@
 #include <infiniband/common.h>
 #include <infiniband/umad.h>
 #include <infiniband/mad.h>
-#include <infiniband/complib/cl_nodenamemap.h>
+#include <complib/cl_nodenamemap.h>
 
 #include "ibdiag_common.h"
 
diff --git a/contrib/ofed/management/infiniband-diags/src/ibsendtrap.c b/contrib/ofed/management/infiniband-diags/src/ibsendtrap.c
index 66620de62e2b..2754dc008dea 100644
--- a/contrib/ofed/management/infiniband-diags/src/ibsendtrap.c
+++ b/contrib/ofed/management/infiniband-diags/src/ibsendtrap.c
@@ -43,7 +43,7 @@
 #include <getopt.h>
 
 #include <infiniband/mad.h>
-#include <infiniband/iba/ib_types.h>
+#include <iba/ib_types.h>
 
 #include "ibdiag_common.h"
 
diff --git a/contrib/ofed/management/infiniband-diags/src/ibtracert.c b/contrib/ofed/management/infiniband-diags/src/ibtracert.c
index bde0ea795326..f8ecf76483cc 100644
--- a/contrib/ofed/management/infiniband-diags/src/ibtracert.c
+++ b/contrib/ofed/management/infiniband-diags/src/ibtracert.c
@@ -49,7 +49,7 @@
 #include <infiniband/common.h>
 #include <infiniband/umad.h>
 #include <infiniband/mad.h>
-#include <infiniband/complib/cl_nodenamemap.h>
+#include <complib/cl_nodenamemap.h>
 
 #include "ibdiag_common.h"
 
diff --git a/contrib/ofed/management/infiniband-diags/src/saquery.c b/contrib/ofed/management/infiniband-diags/src/saquery.c
index 97663d1d538f..9f882e73a401 100644
--- a/contrib/ofed/management/infiniband-diags/src/saquery.c
+++ b/contrib/ofed/management/infiniband-diags/src/saquery.c
@@ -50,12 +50,12 @@
 #include <getopt.h>
 
 #include <infiniband/mad.h>
-#include <infiniband/opensm/osm_log.h>
-#include <infiniband/vendor/osm_vendor_api.h>
-#include <infiniband/vendor/osm_vendor_sa_api.h>
-#include <infiniband/opensm/osm_mad_pool.h>
-#include <infiniband/complib/cl_debug.h>
-#include <infiniband/complib/cl_nodenamemap.h>
+#include <opensm/osm_log.h>
+#include <vendor/osm_vendor_api.h>
+#include <vendor/osm_vendor_sa_api.h>
+#include <opensm/osm_mad_pool.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_nodenamemap.h>
 
 #include <netinet/in.h>
 
diff --git a/contrib/ofed/management/infiniband-diags/src/smpquery.c b/contrib/ofed/management/infiniband-diags/src/smpquery.c
index ed8ec83c9a06..01ccfaf16412 100644
--- a/contrib/ofed/management/infiniband-diags/src/smpquery.c
+++ b/contrib/ofed/management/infiniband-diags/src/smpquery.c
@@ -50,7 +50,7 @@
 #include <infiniband/common.h>
 #include <infiniband/umad.h>
 #include <infiniband/mad.h>
-#include <infiniband/complib/cl_nodenamemap.h>
+#include <complib/cl_nodenamemap.h>
 
 #include "ibdiag_common.h"
 
diff --git a/contrib/ofed/usr.bin/Makefile.inc b/contrib/ofed/usr.bin/Makefile.inc
index e6a0550b82d3..d05778c68d37 100644
--- a/contrib/ofed/usr.bin/Makefile.inc
+++ b/contrib/ofed/usr.bin/Makefile.inc
@@ -1,4 +1,9 @@
 DIAGPATH=	${.CURDIR}/../../management/infiniband-diags
 BINDIR?=	/usr/bin
 CFLAGS+=	-I${.CURDIR}/../../include/infiniband
+CFLAGS+=	-I${.CURDIR}/../../include
 CFLAGS+=	-I${.CURDIR}/../../management/opensm/include/
+CFLAGS+=	-I${.CURDIR}/../../management/opensm
+CFLAGS+=	-I${.CURDIR}/../../management/libibcommon/include
+CFLAGS+=	-I${.CURDIR}/../../management/libibumad/include
+CFLAGS+=	-I${.CURDIR}/../../management/libibmad/include
diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf
index 645a2542848b..4519e87f8458 100644
--- a/etc/defaults/rc.conf
+++ b/etc/defaults/rc.conf
@@ -390,12 +390,6 @@ gateway_enable="NO"		# Set to YES if this host will be a gateway.
 routed_enable="NO"		# Set to YES to enable a routing daemon.
 routed_program="/sbin/routed"	# Name of routing daemon to use if enabled.
 routed_flags="-q"		# Flags for routing daemon.
-mrouted_enable="NO"		# Do IPv4 multicast routing.
-mrouted_program="/usr/local/sbin/mrouted"	# Name of IPv4 multicast
-						# routing daemon.  You need to
-						# install it from package or
-						# port.
-mrouted_flags=""		# Flags for multicast routing daemon.
 arpproxy_all="NO"		# replaces obsolete kernel option ARP_PROXYALL.
 forward_sourceroute="NO"	# do source routing (only if gateway_enable is set to "YES")
 accept_sourceroute="NO"		# accept source routed packets to us
diff --git a/etc/rc b/etc/rc
index 21efc18c8a73..4efc293b6b2b 100644
--- a/etc/rc
+++ b/etc/rc
@@ -69,19 +69,16 @@ fi
 # and to make the configuration file variables available to rc itself.
 #
 . /etc/rc.subr
-load_rc_config 'XXX'
+load_rc_config
 
 # If we receive a SIGALRM, re-source /etc/rc.conf; this allows rc.d
 # scripts to perform "boot-time configuration" including enabling and
 # disabling rc.d scripts which appear later in the boot order.
-trap "_rc_conf_loaded=false; load_rc_config 'XXX'" ALRM
+trap "_rc_conf_loaded=false; load_rc_config" ALRM
 
 skip="-s nostart"
 if [ `/sbin/sysctl -n security.jail.jailed` -eq 1 ]; then
 	skip="$skip -s nojail"
-	if [ "$early_late_divider" = "FILESYSTEMS" ]; then
-		early_late_divider=NETWORKING
-	fi
 	if [ `/sbin/sysctl -n security.jail.vnet` -ne 1 ]; then
 		skip="$skip -s nojailvnet"
 	fi
diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile
index f26c190fe9dd..4994e9da8aa8 100644
--- a/etc/rc.d/Makefile
+++ b/etc/rc.d/Makefile
@@ -90,7 +90,6 @@ FILES=	DAEMON \
 	mountd \
 	moused \
 	mroute6d \
-	mrouted \
 	msgs \
 	natd \
 	netif \
diff --git a/etc/rc.d/NETWORKING b/etc/rc.d/NETWORKING
index 12dd3b0d71b5..750d78af67d9 100755
--- a/etc/rc.d/NETWORKING
+++ b/etc/rc.d/NETWORKING
@@ -5,7 +5,7 @@
 
 # PROVIDE: NETWORKING NETWORK
 # REQUIRE: netif netoptions routing ppp ipfw stf
-# REQUIRE: defaultroute routed mrouted route6d mroute6d resolv bridge
+# REQUIRE: defaultroute routed route6d mroute6d resolv bridge
 # REQUIRE: static_arp static_ndp local_unbound
 
 #	This is a dummy dependency, for services which require networking
diff --git a/etc/rc.d/ipmon b/etc/rc.d/ipmon
index cdd87426695c..8e42a186f438 100755
--- a/etc/rc.d/ipmon
+++ b/etc/rc.d/ipmon
@@ -4,7 +4,7 @@
 #
 
 # PROVIDE: ipmon
-# REQUIRE: FILESYSTEMS hostname sysctl FILESYSTEMS ipfilter
+# REQUIRE: FILESYSTEMS hostname sysctl ipfilter
 # BEFORE:  SERVERS
 # KEYWORD: nojail
 
diff --git a/etc/rc.d/mrouted b/etc/rc.d/mrouted
deleted file mode 100755
index d15299f35ce1..000000000000
--- a/etc/rc.d/mrouted
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/sh
-#
-# $FreeBSD$
-#
-
-# PROVIDE: mrouted
-# REQUIRE: netif routing FILESYSTEMS
-# KEYWORD: nojail
-
-. /etc/rc.subr
-
-name="mrouted"
-rcvar="mrouted_enable"
-command="/usr/local/sbin/${name}"
-pidfile="/var/run/${name}.pid"
-required_files="/etc/${name}.conf"
-extra_commands="reload"
-
-load_rc_config $name
-run_rc_command "$1"
diff --git a/etc/rc.d/pflog b/etc/rc.d/pflog
index 7647ebf676e7..3deceabf2ef9 100755
--- a/etc/rc.d/pflog
+++ b/etc/rc.d/pflog
@@ -4,7 +4,7 @@
 #
 
 # PROVIDE: pflog
-# REQUIRE: FILESYSTEMS netif FILESYSTEMS
+# REQUIRE: FILESYSTEMS netif
 # KEYWORD: nojail
 
 . /etc/rc.subr
diff --git a/etc/rc.subr b/etc/rc.subr
index 6534f6858f65..7b1e38737c10 100644
--- a/etc/rc.subr
+++ b/etc/rc.subr
@@ -1315,9 +1315,6 @@ load_rc_config()
 {
 	local _name _rcvar_val _var _defval _v _msg _new _d
 	_name=$1
-	if [ -z "$_name" ]; then
-		err 3 'USAGE: load_rc_config name'
-	fi
 
 	if ${_rc_conf_loaded:-false}; then
 		:
@@ -1333,20 +1330,24 @@ load_rc_config()
 		_rc_conf_loaded=true
 	fi
 
-	for _d in /etc ${local_startup%*/rc.d}; do
-		if [ -f ${_d}/rc.conf.d/"$_name" ]; then
-			debug "Sourcing ${_d}/rc.conf.d/$_name"
-			. ${_d}/rc.conf.d/"$_name"
-		elif [ -d ${_d}/rc.conf.d/"$_name" ] ; then
-			local _rc
-			for _rc in ${_d}/rc.conf.d/"$_name"/* ; do
-				if [ -f "$_rc" ] ; then
-					debug "Sourcing $_rc"
-					. "$_rc"
-				fi
-			done
-		fi
-	done
+	# If a service name was specified, attempt to load
+	# service-specific configuration
+	if [ -n "$_name" ] ; then
+		for _d in /etc ${local_startup%*/rc.d}; do
+			if [ -f ${_d}/rc.conf.d/"$_name" ]; then
+				debug "Sourcing ${_d}/rc.conf.d/$_name"
+				. ${_d}/rc.conf.d/"$_name"
+			elif [ -d ${_d}/rc.conf.d/"$_name" ] ; then
+				local _rc
+				for _rc in ${_d}/rc.conf.d/"$_name"/* ; do
+					if [ -f "$_rc" ] ; then
+						debug "Sourcing $_rc"
+						. "$_rc"
+					fi
+				done
+			fi
+		done
+	fi
 
 	# Set defaults if defined.
 	for _var in $rcvar $rcvars; do
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile
index 885f8a9922bd..572c0613904c 100644
--- a/sbin/ifconfig/Makefile
+++ b/sbin/ifconfig/Makefile
@@ -30,7 +30,7 @@ SRCS+=	ifmac.c			# MAC support
 SRCS+=	ifmedia.c		# SIOC[GS]IFMEDIA support
 SRCS+=	iffib.c			# non-default FIB support
 SRCS+=	ifvlan.c		# SIOC[GS]ETVLAN support
-SRCS+=	ifvxlan.c		# VXLAN support
+#SRCS+=	ifvxlan.c		# VXLAN support
 SRCS+=	ifgre.c			# GRE keys etc
 SRCS+=	ifgif.c			# GIF reversed header workaround
 
diff --git a/share/man/man4/tap.4 b/share/man/man4/tap.4
index d68dab30b037..229de6028eb3 100644
--- a/share/man/man4/tap.4
+++ b/share/man/man4/tap.4
@@ -1,7 +1,7 @@
 .\" $FreeBSD$
 .\" Based on PR#2411
 .\"
-.Dd November 4, 2014
+.Dd November 30, 2014
 .Dt TAP 4
 .Os
 .Sh NAME
@@ -34,6 +34,17 @@ or a terminal for
 and a character-special device
 .Dq control
 interface.
+A client program transfers Ethernet frames to or from the 
+.Nm
+.Dq control
+interface.
+The
+.Xr tun 4
+interface provides similar functionality at the network layer:
+a client will transfer IP (by default) packets to or from a
+.Xr tun 4
+.Dq control
+interface.
 .Pp
 The network interfaces are named
 .Dq Li tap0 ,
@@ -314,4 +325,5 @@ VMware
 .El
 .Sh SEE ALSO
 .Xr inet 4 ,
-.Xr intro 4
+.Xr intro 4 ,
+.Xr tun 4
diff --git a/share/man/man4/tun.4 b/share/man/man4/tun.4
index b5139a7cdf0d..0b88b7213b07 100644
--- a/share/man/man4/tun.4
+++ b/share/man/man4/tun.4
@@ -2,7 +2,7 @@
 .\" $FreeBSD$
 .\" Based on PR#2411
 .\"
-.Dd February 4, 2007
+.Dd November 30, 2014
 .Dt TUN 4
 .Os
 .Sh NAME
@@ -35,6 +35,17 @@ or a terminal for
 and a character-special device
 .Dq control
 interface.
+A client program transfers IP (by default) packets to or from the 
+.Nm
+.Dq control
+interface.
+The
+.Xr tap 4
+interface provides similar functionality at the Ethernet layer:
+a client will transfer Ethernet frames to or from a
+.Xr tap 4
+.Dq control
+interface.
 .Pp
 The network interfaces are named
 .Dq Li tun0 ,
@@ -307,6 +318,7 @@ them pile up.
 .Xr inet 4 ,
 .Xr intro 4 ,
 .Xr pty 4 ,
+.Xr tap 4 ,
 .Xr ifconfig 8
 .Sh AUTHORS
 This manual page was originally obtained from
diff --git a/sys/arm/arm/cpufunc_asm_armv5.S b/sys/arm/arm/cpufunc_asm_armv5.S
index 7435b462e51b..582ea504c14f 100644
--- a/sys/arm/arm/cpufunc_asm_armv5.S
+++ b/sys/arm/arm/cpufunc_asm_armv5.S
@@ -194,7 +194,6 @@ ENTRY(armv5_idcache_wbinv_range)
 END(armv5_idcache_wbinv_range)
 
 ENTRY_NP(armv5_idcache_wbinv_all)
-armv5_idcache_wbinv_all:
 .Larmv5_idcache_wbinv_all:
 	/*
 	 * We assume that the code here can never be out of sync with the
diff --git a/sys/arm/arm/cpufunc_asm_xscale_c3.S b/sys/arm/arm/cpufunc_asm_xscale_c3.S
index 6766a327156a..78fa2d578dcf 100644
--- a/sys/arm/arm/cpufunc_asm_xscale_c3.S
+++ b/sys/arm/arm/cpufunc_asm_xscale_c3.S
@@ -144,7 +144,6 @@ __FBSDID("$FreeBSD$");
 
 
 ENTRY_NP(xscalec3_cache_syncI)
-xscalec3_cache_purgeID:
 EENTRY_NP(xscalec3_cache_purgeID)
 	mcr	p15, 0, r0, c7, c5, 0	/* flush I cache (D cleaned below) */
 EENTRY_NP(xscalec3_cache_cleanID)
diff --git a/sys/arm/arm/fusu.S b/sys/arm/arm/fusu.S
index c70215c297db..b55f443c2f9f 100644
--- a/sys/arm/arm/fusu.S
+++ b/sys/arm/arm/fusu.S
@@ -129,7 +129,7 @@ EENTRY_NP(fuword32)
 	str	r1, [r2, #PCB_ONFAULT]
 	mov	r0, r3
 	RET
-END(fuword32)
+EEND(fuword32)
 END(fuword)
 
 /*
@@ -295,7 +295,7 @@ EENTRY_NP(suword32)
 	mov	r0, #0x00000000
 	str	r0, [r2, #PCB_ONFAULT]
 	RET
-END(suword32)
+EEND(suword32)
 END(suword)
 
 /*
diff --git a/sys/arm/arm/support.S b/sys/arm/arm/support.S
index 2a6eec9828e0..1714b0f0d203 100644
--- a/sys/arm/arm/support.S
+++ b/sys/arm/arm/support.S
@@ -130,7 +130,7 @@ ENTRY(bzero)
 .Lnormal0:
 	mov	r3, #0x00
 	b	do_memset
-EEND(bzero)
+END(bzero)
 /* LINTSTUB: Func: void *memset(void *, int, size_t) */
 ENTRY(memset)
 	and	r3, r1, #0xff		/* We deal with bytes */
diff --git a/sys/arm/include/asm.h b/sys/arm/include/asm.h
index 9577001917b2..bd4b6361f3cd 100644
--- a/sys/arm/include/asm.h
+++ b/sys/arm/include/asm.h
@@ -57,19 +57,6 @@
 #define	_FNEND
 #endif
 
-/*
- * gas/arm uses @ as a single comment character and thus cannot be used here
- * Instead it recognised the # instead of an @ symbols in .type directives
- * We define a couple of macros so that assembly code will not be dependent
- * on one or the other.
- */
-#define _ASM_TYPE_FUNCTION	#function
-#define _ASM_TYPE_OBJECT	#object
-#define GLOBAL(X) .globl x
-#define _ENTRY(x) \
-	.text; _ALIGN_TEXT; .globl x; .type x,_ASM_TYPE_FUNCTION; x: _FNSTART
-#define	_END(x)	.size x, . - x; _FNEND
-
 /*
  * EENTRY()/EEND() mark "extra" entry/exit points from a function.
  * The unwind info cannot handle the concept of a nested function, or a function
@@ -79,8 +66,21 @@
  * basically just a label that you can jump to.  The EEND() macro does nothing
  * at all, except document the exit point associated with the same-named entry.
  */
-#define _EENTRY(x) 	.globl x; .type x,_ASM_TYPE_FUNCTION; x:
-#define _EEND(x)	/* nothing */
+#define	_EENTRY(x) 	.globl x; .type x,_ASM_TYPE_FUNCTION; x:
+#define	_EEND(x)	/* nothing */
+
+/*
+ * gas/arm uses @ as a single comment character and thus cannot be used here
+ * Instead it recognised the # instead of an @ symbols in .type directives
+ * We define a couple of macros so that assembly code will not be dependent
+ * on one or the other.
+ */
+#define _ASM_TYPE_FUNCTION	#function
+#define _ASM_TYPE_OBJECT	#object
+#define GLOBAL(X) .globl x
+#define	_ENTRY(x) \
+	.text; _ALIGN_TEXT; _EENTRY(x) _FNSTART
+#define	_END(x)	.size x, . - x; _FNEND
 
 #ifdef GPROF
 #  define _PROF_PROLOGUE	\
diff --git a/sys/boot/i386/boot2/boot2.c b/sys/boot/i386/boot2/boot2.c
index 001126fb83f8..75abc7e895e7 100644
--- a/sys/boot/i386/boot2/boot2.c
+++ b/sys/boot/i386/boot2/boot2.c
@@ -418,7 +418,7 @@ parse()
 #if SERIAL
 		} else if (c == 'S') {
 		    j = 0;
-		    while ((i = *arg++ - '0') <= 9)
+		    while ((unsigned int)(i = *arg++ - '0') <= 9)
 			j = j * 10 + i;
 		    if (j > 0 && i == -'0') {
 			comspeed = j;
diff --git a/sys/dev/bxe/bxe.c b/sys/dev/bxe/bxe.c
index a27b3e7a56bd..3509f2d023df 100644
--- a/sys/dev/bxe/bxe.c
+++ b/sys/dev/bxe/bxe.c
@@ -3219,7 +3219,7 @@ bxe_tpa_stop(struct bxe_softc          *sc,
 #if __FreeBSD_version >= 800000
         /* specify what RSS queue was used for this flow */
         m->m_pkthdr.flowid = fp->index;
-        m->m_flags |= M_FLOWID;
+        M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
 #endif
 
         if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
@@ -3454,7 +3454,7 @@ bxe_rxeof(struct bxe_softc    *sc,
 #if __FreeBSD_version >= 800000
         /* specify what RSS queue was used for this flow */
         m->m_pkthdr.flowid = fp->index;
-        m->m_flags |= M_FLOWID;
+        M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
 #endif
 
 next_rx:
@@ -6037,10 +6037,9 @@ bxe_tx_mq_start(struct ifnet *ifp,
 
     fp_index = 0; /* default is the first queue */
 
-    /* change the queue if using flow ID */
-    if ((m->m_flags & M_FLOWID) != 0) {
+    /* check if flowid is set */
+    if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
         fp_index = (m->m_pkthdr.flowid % sc->num_queues);
-    }
 
     fp = &sc->fp[fp_index];
 
diff --git a/sys/dev/cxgb/cxgb_sge.c b/sys/dev/cxgb/cxgb_sge.c
index a7f39a510109..2b08183b0cd5 100644
--- a/sys/dev/cxgb/cxgb_sge.c
+++ b/sys/dev/cxgb/cxgb_sge.c
@@ -1733,8 +1733,9 @@ cxgb_transmit(struct ifnet *ifp, struct mbuf *m)
 		m_freem(m);
 		return (0);
 	}
-	
-	if (m->m_flags & M_FLOWID)
+
+	/* check if flowid is set */
+	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)	
 		qidx = (m->m_pkthdr.flowid % pi->nqsets) + pi->first_qset;
 
 	qs = &pi->adapter->sge.qs[qidx];
@@ -2899,9 +2900,10 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget)
 			
 			eop = get_packet(adap, drop_thresh, qs, mh, r);
 			if (eop) {
-				if (r->rss_hdr.hash_type && !adap->timestamp)
-					mh->mh_head->m_flags |= M_FLOWID;
-				mh->mh_head->m_pkthdr.flowid = rss_hash;
+				if (r->rss_hdr.hash_type && !adap->timestamp) {
+					M_HASHTYPE_SET(mh->mh_head, M_HASHTYPE_OPAQUE);
+					mh->mh_head->m_pkthdr.flowid = rss_hash;
+				}
 			}
 			
 			ethpad = 2;
diff --git a/sys/dev/cxgb/ulp/tom/cxgb_cpl_io.c b/sys/dev/cxgb/ulp/tom/cxgb_cpl_io.c
index 81a446a64a4f..a4b67088db93 100644
--- a/sys/dev/cxgb/ulp/tom/cxgb_cpl_io.c
+++ b/sys/dev/cxgb/ulp/tom/cxgb_cpl_io.c
@@ -1199,7 +1199,7 @@ do_rx_data(struct sge_qset *qs, struct rsp_desc *r, struct mbuf *m)
 	}
 
 	toep->tp_enqueued += m->m_pkthdr.len;
-	sbappendstream_locked(so_rcv, m);
+	sbappendstream_locked(so_rcv, m, 0);
 	sorwakeup_locked(so);
 	SOCKBUF_UNLOCK_ASSERT(so_rcv);
 
diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c
index f9caf2eec1d8..2c384fd0f1a6 100644
--- a/sys/dev/cxgbe/t4_main.c
+++ b/sys/dev/cxgbe/t4_main.c
@@ -1440,7 +1440,8 @@ cxgbe_transmit(struct ifnet *ifp, struct mbuf *m)
 		return (ENETDOWN);
 	}
 
-	if (m->m_flags & M_FLOWID)
+	/* check if flowid is set */
+	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
 		txq += ((m->m_pkthdr.flowid % (pi->ntxq - pi->rsrv_noflowq))
 		    + pi->rsrv_noflowq);
 	br = txq->br;
diff --git a/sys/dev/cxgbe/t4_sge.c b/sys/dev/cxgbe/t4_sge.c
index 499f25205998..58940fe4959c 100644
--- a/sys/dev/cxgbe/t4_sge.c
+++ b/sys/dev/cxgbe/t4_sge.c
@@ -1734,7 +1734,7 @@ t4_eth_rx(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m0)
 	m0->m_data += fl_pktshift;
 
 	m0->m_pkthdr.rcvif = ifp;
-	m0->m_flags |= M_FLOWID;
+	M_HASHTYPE_SET(m0, M_HASHTYPE_OPAQUE);
 	m0->m_pkthdr.flowid = be32toh(rss->hash_val);
 
 	if (cpl->csum_calc && !cpl->err_vec) {
diff --git a/sys/dev/cxgbe/tom/t4_cpl_io.c b/sys/dev/cxgbe/tom/t4_cpl_io.c
index 29e5fa243be5..5dc843428448 100644
--- a/sys/dev/cxgbe/tom/t4_cpl_io.c
+++ b/sys/dev/cxgbe/tom/t4_cpl_io.c
@@ -1086,7 +1086,7 @@ do_peer_close(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
 #ifdef USE_DDP_RX_FLOW_CONTROL
 		toep->rx_credits -= m->m_len;	/* adjust for F_RX_FC_DDP */
 #endif
-		sbappendstream_locked(sb, m);
+		sbappendstream_locked(sb, m, 0);
 		toep->sb_cc = sbused(sb);
 	}
 	socantrcvmore_locked(so);	/* unlocks the sockbuf */
@@ -1586,7 +1586,7 @@ do_rx_data(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
 	    ("%s: sb %p has more data (%d) than last time (%d).",
 	    __func__, sb, sbused(sb), toep->sb_cc));
 	toep->rx_credits += toep->sb_cc - sbused(sb);
-	sbappendstream_locked(sb, m);
+	sbappendstream_locked(sb, m, 0);
 	toep->sb_cc = sbused(sb);
 	sorwakeup_locked(so);
 	SOCKBUF_UNLOCK_ASSERT(sb);
diff --git a/sys/dev/cxgbe/tom/t4_ddp.c b/sys/dev/cxgbe/tom/t4_ddp.c
index 89585cf83039..17eb071b3cb7 100644
--- a/sys/dev/cxgbe/tom/t4_ddp.c
+++ b/sys/dev/cxgbe/tom/t4_ddp.c
@@ -231,7 +231,7 @@ insert_ddp_data(struct toepcb *toep, uint32_t n)
 #ifdef USE_DDP_RX_FLOW_CONTROL
 	toep->rx_credits -= n;	/* adjust for F_RX_FC_DDP */
 #endif
-	sbappendstream_locked(sb, m);
+	sbappendstream_locked(sb, m, 0);
 	toep->sb_cc = sbused(sb);
 }
 
@@ -466,7 +466,7 @@ handle_ddp_data(struct toepcb *toep, __be32 ddp_report, __be32 rcv_nxt, int len)
 #ifdef USE_DDP_RX_FLOW_CONTROL
 	toep->rx_credits -= len;	/* adjust for F_RX_FC_DDP */
 #endif
-	sbappendstream_locked(sb, m);
+	sbappendstream_locked(sb, m, 0);
 	toep->sb_cc = sbused(sb);
 wakeup:
 	KASSERT(toep->ddp_flags & db_flag,
@@ -971,8 +971,9 @@ handle_ddp(struct socket *so, struct uio *uio, int flags, int error)
 	 */
 	rc = sbwait(sb);
 	while (toep->ddp_flags & buf_flag) {
+		/* XXXGL: shouldn't here be sbwait() call? */
 		sb->sb_flags |= SB_WAIT;
-		msleep(&sb->sb_cc, &sb->sb_mtx, PSOCK , "sbwait", 0);
+		msleep(&sb->sb_acc, &sb->sb_mtx, PSOCK , "sbwait", 0);
 	}
 	unwire_ddp_buffer(db);
 	return (rc);
diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c
index 335aa01d95c9..75f0fb419d50 100644
--- a/sys/dev/e1000/if_igb.c
+++ b/sys/dev/e1000/if_igb.c
@@ -990,7 +990,7 @@ igb_mq_start(struct ifnet *ifp, struct mbuf *m)
 	 * If everything is setup correctly, it should be the
 	 * same bucket that the current CPU we're on is.
 	 */
-	if ((m->m_flags & M_FLOWID) != 0) {
+	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
 #ifdef	RSS
 		if (rss_hash2bucket(m->m_pkthdr.flowid,
 		    M_HASHTYPE_GET(m), &bucket_id) == 0) {
@@ -5166,7 +5166,6 @@ igb_rxeof(struct igb_queue *que, int count, int *done)
 			/* XXX set flowtype once this works right */
 			rxr->fmp->m_pkthdr.flowid = 
 			    le32toh(cur->wb.lower.hi_dword.rss);
-			rxr->fmp->m_flags |= M_FLOWID;
 			switch (pkt_info & E1000_RXDADV_RSSTYPE_MASK) {
 			case E1000_RXDADV_RSSTYPE_IPV4_TCP:
 				M_HASHTYPE_SET(rxr->fmp, M_HASHTYPE_RSS_TCP_IPV4);
@@ -5196,11 +5195,11 @@ igb_rxeof(struct igb_queue *que, int count, int *done)
 			
 			default:
 				/* XXX fallthrough */
-				M_HASHTYPE_SET(rxr->fmp, M_HASHTYPE_NONE);
+				M_HASHTYPE_SET(rxr->fmp, M_HASHTYPE_OPAQUE);
 			}
 #elif !defined(IGB_LEGACY_TX)
 			rxr->fmp->m_pkthdr.flowid = que->msix;
-			rxr->fmp->m_flags |= M_FLOWID;
+			M_HASHTYPE_SET(rxr->fmp, M_HASHTYPE_OPAQUE);
 #endif
 			sendmp = rxr->fmp;
 			/* Make sure to set M_PKTHDR. */
diff --git a/sys/dev/ixgbe/ixgbe.c b/sys/dev/ixgbe/ixgbe.c
index 9ac70eeac5e4..2fd126c5396e 100644
--- a/sys/dev/ixgbe/ixgbe.c
+++ b/sys/dev/ixgbe/ixgbe.c
@@ -833,7 +833,7 @@ ixgbe_mq_start(struct ifnet *ifp, struct mbuf *m)
 	 * If everything is setup correctly, it should be the
 	 * same bucket that the current CPU we're on is.
 	 */
-	if ((m->m_flags & M_FLOWID) != 0) {
+	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
 #ifdef	RSS
 		if (rss_hash2bucket(m->m_pkthdr.flowid,
 		    M_HASHTYPE_GET(m), &bucket_id) == 0) {
@@ -4764,7 +4764,6 @@ ixgbe_rxeof(struct ix_queue *que)
 #ifdef RSS
 			sendmp->m_pkthdr.flowid =
 			    le32toh(cur->wb.lower.hi_dword.rss);
-			sendmp->m_flags |= M_FLOWID;
 			switch (pkt_info & IXGBE_RXDADV_RSSTYPE_MASK) {
 			case IXGBE_RXDADV_RSSTYPE_IPV4_TCP:
 				M_HASHTYPE_SET(sendmp, M_HASHTYPE_RSS_TCP_IPV4);
@@ -4795,11 +4794,12 @@ ixgbe_rxeof(struct ix_queue *que)
 				break;
 			default:
 				/* XXX fallthrough */
-				M_HASHTYPE_SET(sendmp, M_HASHTYPE_NONE);
+				M_HASHTYPE_SET(sendmp, M_HASHTYPE_OPAQUE);
+				break;
 			}
 #else /* RSS */
 			sendmp->m_pkthdr.flowid = que->msix;
-			sendmp->m_flags |= M_FLOWID;
+			M_HASHTYPE_SET(sendmp, M_HASHTYPE_OPAQUE);
 #endif /* RSS */
 #endif /* FreeBSD_version */
 		}
diff --git a/sys/dev/ixgbe/ixv.c b/sys/dev/ixgbe/ixv.c
index 1d77e8b5a27a..edbdfca85920 100644
--- a/sys/dev/ixgbe/ixv.c
+++ b/sys/dev/ixgbe/ixv.c
@@ -580,7 +580,7 @@ ixv_mq_start(struct ifnet *ifp, struct mbuf *m)
 	int 		i = 0, err = 0;
 
 	/* Which queue to use */
-	if ((m->m_flags & M_FLOWID) != 0)
+	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
 		i = m->m_pkthdr.flowid % adapter->num_queues;
 
 	txr = &adapter->tx_rings[i];
@@ -3464,7 +3464,7 @@ ixv_rxeof(struct ix_queue *que, int count)
 				ixv_rx_checksum(staterr, sendmp, ptype);
 #if __FreeBSD_version >= 800000
 			sendmp->m_pkthdr.flowid = que->msix;
-			sendmp->m_flags |= M_FLOWID;
+			M_HASHTYPE_SET(sendmp, M_HASHTYPE_OPAQUE);
 #endif
 		}
 next_desc:
diff --git a/sys/dev/ixl/ixl_txrx.c b/sys/dev/ixl/ixl_txrx.c
index 6322f2c9fd0e..f36b8318961d 100755
--- a/sys/dev/ixl/ixl_txrx.c
+++ b/sys/dev/ixl/ixl_txrx.c
@@ -66,8 +66,8 @@ ixl_mq_start(struct ifnet *ifp, struct mbuf *m)
 	struct tx_ring		*txr;
 	int 			err, i;
 
-	/* Which queue to use */
-	if ((m->m_flags & M_FLOWID) != 0)
+	/* check if flowid is set */
+	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
 		i = m->m_pkthdr.flowid % vsi->num_queues;
 	else
 		i = curcpu % vsi->num_queues;
@@ -1543,7 +1543,7 @@ ixl_rxeof(struct ixl_queue *que, int count)
 			if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
 				ixl_rx_checksum(sendmp, status, error, ptype);
 			sendmp->m_pkthdr.flowid = que->msix;
-			sendmp->m_flags |= M_FLOWID;
+			M_HASHTYPE_SET(sendmp, M_HASHTYPE_OPAQUE);
 		}
 next_desc:
 		bus_dmamap_sync(rxr->dma.tag, rxr->dma.map,
diff --git a/sys/dev/mxge/if_mxge.c b/sys/dev/mxge/if_mxge.c
index e97ae5c7130e..fe8c08a72495 100644
--- a/sys/dev/mxge/if_mxge.c
+++ b/sys/dev/mxge/if_mxge.c
@@ -2719,7 +2719,7 @@ mxge_rx_done_big(struct mxge_slice_state *ss, uint32_t len,
 	/* flowid only valid if RSS hashing is enabled */
 	if (sc->num_slices > 1) {
 		m->m_pkthdr.flowid = (ss - sc->ss);
-		m->m_flags |= M_FLOWID;
+		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
 	}
 	/* pass the frame up the stack */
 	(*ifp->if_input)(ifp, m);
@@ -2787,7 +2787,7 @@ mxge_rx_done_small(struct mxge_slice_state *ss, uint32_t len,
 	/* flowid only valid if RSS hashing is enabled */
 	if (sc->num_slices > 1) {
 		m->m_pkthdr.flowid = (ss - sc->ss);
-		m->m_flags |= M_FLOWID;
+		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
 	}
 	/* pass the frame up the stack */
 	(*ifp->if_input)(ifp, m);
diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c
index 322670814553..dd968ca51577 100644
--- a/sys/dev/netmap/netmap_freebsd.c
+++ b/sys/dev/netmap/netmap_freebsd.c
@@ -204,7 +204,7 @@ netmap_catch_tx(struct netmap_generic_adapter *gna, int enable)
  * of the transmission does not consume resources.
  *
  * On FreeBSD, and on multiqueue cards, we can force the queue using
- *      if ((m->m_flags & M_FLOWID) != 0)
+ *      if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
  *              i = m->m_pkthdr.flowid % adapter->num_queues;
  *      else
  *              i = curcpu % adapter->num_queues;
@@ -240,7 +240,7 @@ generic_xmit_frame(struct ifnet *ifp, struct mbuf *m,
 	m->m_len = m->m_pkthdr.len = len;
 	// inc refcount. All ours, we could skip the atomic
 	atomic_fetchadd_int(PNT_MBUF_REFCNT(m), 1);
-	m->m_flags |= M_FLOWID;
+	M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
 	m->m_pkthdr.flowid = ring_nr;
 	m->m_pkthdr.rcvif = ifp; /* used for tx notification */
 	ret = NA(ifp)->if_transmit(ifp, m);
diff --git a/sys/dev/oce/oce_if.c b/sys/dev/oce/oce_if.c
index fe48007e8973..062181b2367b 100644
--- a/sys/dev/oce/oce_if.c
+++ b/sys/dev/oce/oce_if.c
@@ -563,7 +563,7 @@ oce_multiq_start(struct ifnet *ifp, struct mbuf *m)
 	int queue_index = 0;
 	int status = 0;
 
-	if ((m->m_flags & M_FLOWID) != 0)
+	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
 		queue_index = m->m_pkthdr.flowid % sc->nwqs;
 
 	wq = sc->wq[queue_index];
@@ -1374,7 +1374,7 @@ oce_rx(struct oce_rq *rq, uint32_t rqe_idx, struct oce_nic_rx_cqe *cqe)
 			m->m_pkthdr.flowid = (rq->queue_index - 1);
 		else
 			m->m_pkthdr.flowid = rq->queue_index;
-		m->m_flags |= M_FLOWID;
+		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
 #endif
 		/* This deternies if vlan tag is Valid */
 		if (oce_cqe_vtp_valid(sc, cqe)) { 
diff --git a/sys/dev/qlxgbe/ql_isr.c b/sys/dev/qlxgbe/ql_isr.c
index db0029822927..dee8e198e8f4 100644
--- a/sys/dev/qlxgbe/ql_isr.c
+++ b/sys/dev/qlxgbe/ql_isr.c
@@ -159,7 +159,7 @@ qla_rx_intr(qla_host_t *ha, qla_sgl_rcv_t *sgc, uint32_t sds_idx)
 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
 
 	mpf->m_pkthdr.flowid = sgc->rss_hash;
-	mpf->m_flags |= M_FLOWID;
+	M_HASHTYPE_SET(mpf, M_HASHTYPE_OPAQUE);
 
 	(*ifp->if_input)(ifp, mpf);
 
@@ -324,7 +324,7 @@ qla_lro_intr(qla_host_t *ha, qla_sgl_lro_t *sgc, uint32_t sds_idx)
 	mpf->m_pkthdr.csum_data = 0xFFFF;
 
 	mpf->m_pkthdr.flowid = sgc->rss_hash;
-	mpf->m_flags |= M_FLOWID;
+	M_HASHTYPE_SET(mpf, M_HASHTYPE_OPAQUE);
 
 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
 
diff --git a/sys/dev/qlxgbe/ql_os.c b/sys/dev/qlxgbe/ql_os.c
index 1684c070fcd8..04fbf7195529 100644
--- a/sys/dev/qlxgbe/ql_os.c
+++ b/sys/dev/qlxgbe/ql_os.c
@@ -1140,7 +1140,8 @@ qla_send(qla_host_t *ha, struct mbuf **m_headp)
 
 	QL_DPRINT8(ha, (ha->pci_dev, "%s: enter\n", __func__));
 
-	if (m_head->m_flags & M_FLOWID)
+	/* check if flowid is set */
+	if (M_HASHTYPE_GET(m_head) != M_HASHTYPE_NONE)
 		txr_idx = m_head->m_pkthdr.flowid & (ha->hw.num_tx_rings - 1);
 
 	tx_idx = ha->hw.tx_cntxt[txr_idx].txr_next;
diff --git a/sys/dev/qlxge/qls_isr.c b/sys/dev/qlxge/qls_isr.c
index 14b4839be913..03b3a3c52152 100644
--- a/sys/dev/qlxge/qls_isr.c
+++ b/sys/dev/qlxge/qls_isr.c
@@ -190,7 +190,7 @@ qls_rx_comp(qla_host_t *ha, uint32_t rxr_idx, uint32_t cq_idx, q81_rx_t *cq_e)
 			if ((cq_e->flags1 & Q81_RX_FLAGS1_RSS_MATCH_MASK)) {
 				rxr->rss_int++;
 				mp->m_pkthdr.flowid = cq_e->rss;
-				mp->m_flags |= M_FLOWID;
+				M_HASHTYPE_SET(mp, M_HASHTYPE_OPAQUE);
 			}
 			if (cq_e->flags0 & (Q81_RX_FLAGS0_TE |
 				Q81_RX_FLAGS0_NU | Q81_RX_FLAGS0_IE)) {
diff --git a/sys/dev/qlxge/qls_os.c b/sys/dev/qlxge/qls_os.c
index 4f4097935f0c..1617d24095e1 100644
--- a/sys/dev/qlxge/qls_os.c
+++ b/sys/dev/qlxge/qls_os.c
@@ -1136,7 +1136,8 @@ qls_send(qla_host_t *ha, struct mbuf **m_headp)
 
 	QL_DPRINT8((ha->pci_dev, "%s: enter\n", __func__));
 
-	if (m_head->m_flags & M_FLOWID)
+	/* check if flowid is set */
+	if (M_HASHTYPE_GET(m_head) != M_HASHTYPE_NONE)
 		txr_idx = m_head->m_pkthdr.flowid & (ha->num_tx_rings - 1);
 
 	tx_idx = ha->tx_ring[txr_idx].txr_next;
diff --git a/sys/dev/sfxge/sfxge_rx.c b/sys/dev/sfxge/sfxge_rx.c
index 66083d832857..ccfdfb023d07 100644
--- a/sys/dev/sfxge/sfxge_rx.c
+++ b/sys/dev/sfxge/sfxge_rx.c
@@ -302,7 +302,7 @@ sfxge_rx_deliver(struct sfxge_softc *sc, struct sfxge_rx_sw_desc *rx_desc)
 	if (rx_desc->flags & EFX_PKT_TCP) {
 		m->m_pkthdr.flowid = EFX_RX_HASH_VALUE(EFX_RX_HASHALG_TOEPLITZ,
 						       mtod(m, uint8_t *));
-		m->m_flags |= M_FLOWID;
+		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
 	}
 #endif
 	m->m_data += sc->rx_prefix_size;
@@ -353,7 +353,7 @@ sfxge_lro_deliver(struct sfxge_lro_state *st, struct sfxge_lro_conn *c)
 
 #ifdef SFXGE_HAVE_MQ
 	m->m_pkthdr.flowid = c->conn_hash;
-	m->m_flags |= M_FLOWID;
+	M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
 #endif
 	m->m_pkthdr.csum_flags = csum_flags;
 	__sfxge_rx_deliver(sc, m);
diff --git a/sys/dev/sfxge/sfxge_tx.c b/sys/dev/sfxge/sfxge_tx.c
index a12c74756ea5..3fb76d92b6db 100644
--- a/sys/dev/sfxge/sfxge_tx.c
+++ b/sys/dev/sfxge/sfxge_tx.c
@@ -631,7 +631,8 @@ sfxge_if_transmit(struct ifnet *ifp, struct mbuf *m)
 	if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | CSUM_TSO)) {
 		int index = 0;
 
-		if (m->m_flags & M_FLOWID) {
+		/* check if flowid is set */
+		if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
 			uint32_t hash = m->m_pkthdr.flowid;
 
 			index = sc->rx_indir_table[hash % SFXGE_RX_SCALE_MAX];
diff --git a/sys/dev/virtio/block/virtio_blk.c b/sys/dev/virtio/block/virtio_blk.c
index b15cb75a3f40..a65e23d37b4c 100644
--- a/sys/dev/virtio/block/virtio_blk.c
+++ b/sys/dev/virtio/block/virtio_blk.c
@@ -58,7 +58,6 @@ struct vtblk_request {
 	struct virtio_blk_outhdr	 vbr_hdr;
 	struct bio			*vbr_bp;
 	uint8_t				 vbr_ack;
-
 	TAILQ_ENTRY(vtblk_request)	 vbr_link;
 };
 
@@ -132,53 +131,60 @@ static int	vtblk_dump(void *, void *, vm_offset_t, off_t, size_t);
 static void	vtblk_strategy(struct bio *);
 
 static void	vtblk_negotiate_features(struct vtblk_softc *);
+static void	vtblk_setup_features(struct vtblk_softc *);
 static int	vtblk_maximum_segments(struct vtblk_softc *,
 		    struct virtio_blk_config *);
 static int	vtblk_alloc_virtqueue(struct vtblk_softc *);
 static void	vtblk_resize_disk(struct vtblk_softc *, uint64_t);
-static void	vtblk_set_write_cache(struct vtblk_softc *, int);
-static int	vtblk_write_cache_enabled(struct vtblk_softc *sc,
-		    struct virtio_blk_config *);
-static int	vtblk_write_cache_sysctl(SYSCTL_HANDLER_ARGS);
 static void	vtblk_alloc_disk(struct vtblk_softc *,
 		    struct virtio_blk_config *);
 static void	vtblk_create_disk(struct vtblk_softc *);
 
-static int	vtblk_quiesce(struct vtblk_softc *);
-static void	vtblk_startio(struct vtblk_softc *);
-static struct vtblk_request * vtblk_bio_request(struct vtblk_softc *);
-static int	vtblk_execute_request(struct vtblk_softc *,
+static int	vtblk_request_prealloc(struct vtblk_softc *);
+static void	vtblk_request_free(struct vtblk_softc *);
+static struct vtblk_request *
+		vtblk_request_dequeue(struct vtblk_softc *);
+static void	vtblk_request_enqueue(struct vtblk_softc *,
 		    struct vtblk_request *);
-
-static void	vtblk_vq_intr(void *);
-
-static void	vtblk_stop(struct vtblk_softc *);
-
-static void	vtblk_read_config(struct vtblk_softc *,
-		    struct virtio_blk_config *);
-static void	vtblk_get_ident(struct vtblk_softc *);
-static void	vtblk_prepare_dump(struct vtblk_softc *);
-static int	vtblk_write_dump(struct vtblk_softc *, void *, off_t, size_t);
-static int	vtblk_flush_dump(struct vtblk_softc *);
-static int	vtblk_poll_request(struct vtblk_softc *,
+static struct vtblk_request *
+		vtblk_request_next_ready(struct vtblk_softc *);
+static void	vtblk_request_requeue_ready(struct vtblk_softc *,
 		    struct vtblk_request *);
+static struct vtblk_request *
+		vtblk_request_next(struct vtblk_softc *);
+static struct vtblk_request *
+		vtblk_request_bio(struct vtblk_softc *);
+static int	vtblk_request_execute(struct vtblk_softc *,
+		    struct vtblk_request *);
+static int	vtblk_request_error(struct vtblk_request *);
 
-static void	vtblk_finish_completed(struct vtblk_softc *);
+static void	vtblk_queue_completed(struct vtblk_softc *,
+		    struct bio_queue *);
+static void	vtblk_done_completed(struct vtblk_softc *,
+		    struct bio_queue *);
 static void	vtblk_drain_vq(struct vtblk_softc *, int);
 static void	vtblk_drain(struct vtblk_softc *);
 
-static int	vtblk_alloc_requests(struct vtblk_softc *);
-static void	vtblk_free_requests(struct vtblk_softc *);
-static struct vtblk_request * vtblk_dequeue_request(struct vtblk_softc *);
-static void	vtblk_enqueue_request(struct vtblk_softc *,
-		    struct vtblk_request *);
+static void	vtblk_startio(struct vtblk_softc *);
+static void	vtblk_bio_done(struct vtblk_softc *, struct bio *, int);
 
-static struct vtblk_request * vtblk_dequeue_ready(struct vtblk_softc *);
-static void	vtblk_enqueue_ready(struct vtblk_softc *,
+static void	vtblk_read_config(struct vtblk_softc *,
+		    struct virtio_blk_config *);
+static void	vtblk_ident(struct vtblk_softc *);
+static int	vtblk_poll_request(struct vtblk_softc *,
 		    struct vtblk_request *);
+static int	vtblk_quiesce(struct vtblk_softc *);
+static void	vtblk_vq_intr(void *);
+static void	vtblk_stop(struct vtblk_softc *);
 
-static int	vtblk_request_error(struct vtblk_request *);
-static void	vtblk_finish_bio(struct bio *, int);
+static void	vtblk_dump_prepare(struct vtblk_softc *);
+static int	vtblk_dump_write(struct vtblk_softc *, void *, off_t, size_t);
+static int	vtblk_dump_flush(struct vtblk_softc *);
+
+static void	vtblk_set_write_cache(struct vtblk_softc *, int);
+static int	vtblk_write_cache_enabled(struct vtblk_softc *sc,
+		    struct virtio_blk_config *);
+static int	vtblk_write_cache_sysctl(SYSCTL_HANDLER_ARGS);
 
 static void	vtblk_setup_sysctl(struct vtblk_softc *);
 static int	vtblk_tunable_int(struct vtblk_softc *, const char *, int);
@@ -290,30 +296,18 @@ vtblk_attach(device_t dev)
 	struct virtio_blk_config blkcfg;
 	int error;
 
+	virtio_set_feature_desc(dev, vtblk_feature_desc);
+
 	sc = device_get_softc(dev);
 	sc->vtblk_dev = dev;
-
 	VTBLK_LOCK_INIT(sc, device_get_nameunit(dev));
-
 	bioq_init(&sc->vtblk_bioq);
 	TAILQ_INIT(&sc->vtblk_req_free);
 	TAILQ_INIT(&sc->vtblk_req_ready);
 
-	virtio_set_feature_desc(dev, vtblk_feature_desc);
-	vtblk_negotiate_features(sc);
-
-	if (virtio_with_feature(dev, VIRTIO_RING_F_INDIRECT_DESC))
-		sc->vtblk_flags |= VTBLK_FLAG_INDIRECT;
-	if (virtio_with_feature(dev, VIRTIO_BLK_F_RO))
-		sc->vtblk_flags |= VTBLK_FLAG_READONLY;
-	if (virtio_with_feature(dev, VIRTIO_BLK_F_BARRIER))
-		sc->vtblk_flags |= VTBLK_FLAG_BARRIER;
-	if (virtio_with_feature(dev, VIRTIO_BLK_F_CONFIG_WCE))
-		sc->vtblk_flags |= VTBLK_FLAG_WC_CONFIG;
-
 	vtblk_setup_sysctl(sc);
+	vtblk_setup_features(sc);
 
-	/* Get local copy of config. */
 	vtblk_read_config(sc, &blkcfg);
 
 	/*
@@ -352,7 +346,7 @@ vtblk_attach(device_t dev)
 		goto fail;
 	}
 
-	error = vtblk_alloc_requests(sc);
+	error = vtblk_request_prealloc(sc);
 	if (error) {
 		device_printf(dev, "cannot preallocate requests\n");
 		goto fail;
@@ -519,14 +513,14 @@ vtblk_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset,
 	VTBLK_LOCK(sc);
 
 	if ((sc->vtblk_flags & VTBLK_FLAG_DUMPING) == 0) {
-		vtblk_prepare_dump(sc);
+		vtblk_dump_prepare(sc);
 		sc->vtblk_flags |= VTBLK_FLAG_DUMPING;
 	}
 
 	if (length > 0)
-		error = vtblk_write_dump(sc, virtual, offset, length);
+		error = vtblk_dump_write(sc, virtual, offset, length);
 	else if (virtual == NULL && offset == 0)
-		error = vtblk_flush_dump(sc);
+		error = vtblk_dump_flush(sc);
 	else {
 		error = EINVAL;
 		sc->vtblk_flags &= ~VTBLK_FLAG_DUMPING;
@@ -543,7 +537,7 @@ vtblk_strategy(struct bio *bp)
 	struct vtblk_softc *sc;
 
 	if ((sc = bp->bio_disk->d_drv1) == NULL) {
-		vtblk_finish_bio(bp, EINVAL);
+		vtblk_bio_done(NULL, bp, EINVAL);
 		return;
 	}
 
@@ -553,37 +547,21 @@ vtblk_strategy(struct bio *bp)
 	 */
 	if (sc->vtblk_flags & VTBLK_FLAG_READONLY &&
 	    (bp->bio_cmd == BIO_WRITE || bp->bio_cmd == BIO_FLUSH)) {
-		vtblk_finish_bio(bp, EROFS);
+		vtblk_bio_done(sc, bp, EROFS);
 		return;
 	}
 
-#ifdef INVARIANTS
-	/*
-	 * Prevent read/write buffers spanning too many segments from
-	 * getting into the queue. This should only trip if d_maxsize
-	 * was incorrectly set.
-	 */
-	if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
-		int nsegs, max_nsegs;
-
-		nsegs = sglist_count(bp->bio_data, bp->bio_bcount);
-		max_nsegs = sc->vtblk_max_nsegs - VTBLK_MIN_SEGMENTS;
-
-		KASSERT(nsegs <= max_nsegs,
-		    ("%s: bio %p spanned too many segments: %d, max: %d",
-		    __func__, bp, nsegs, max_nsegs));
-	}
-#endif
-
 	VTBLK_LOCK(sc);
-	if (sc->vtblk_flags & VTBLK_FLAG_DETACH)
-		vtblk_finish_bio(bp, ENXIO);
-	else {
-		bioq_insert_tail(&sc->vtblk_bioq, bp);
 
-		if ((sc->vtblk_flags & VTBLK_FLAG_SUSPEND) == 0)
-			vtblk_startio(sc);
+	if (sc->vtblk_flags & VTBLK_FLAG_DETACH) {
+		VTBLK_UNLOCK(sc);
+		vtblk_bio_done(sc, bp, ENXIO);
+		return;
 	}
+
+	bioq_insert_tail(&sc->vtblk_bioq, bp);
+	vtblk_startio(sc);
+
 	VTBLK_UNLOCK(sc);
 }
 
@@ -599,6 +577,25 @@ vtblk_negotiate_features(struct vtblk_softc *sc)
 	sc->vtblk_features = virtio_negotiate_features(dev, features);
 }
 
+static void
+vtblk_setup_features(struct vtblk_softc *sc)
+{
+	device_t dev;
+
+	dev = sc->vtblk_dev;
+
+	vtblk_negotiate_features(sc);
+
+	if (virtio_with_feature(dev, VIRTIO_RING_F_INDIRECT_DESC))
+		sc->vtblk_flags |= VTBLK_FLAG_INDIRECT;
+	if (virtio_with_feature(dev, VIRTIO_BLK_F_RO))
+		sc->vtblk_flags |= VTBLK_FLAG_READONLY;
+	if (virtio_with_feature(dev, VIRTIO_BLK_F_BARRIER))
+		sc->vtblk_flags |= VTBLK_FLAG_BARRIER;
+	if (virtio_with_feature(dev, VIRTIO_BLK_F_CONFIG_WCE))
+		sc->vtblk_flags |= VTBLK_FLAG_WC_CONFIG;
+}
+
 static int
 vtblk_maximum_segments(struct vtblk_softc *sc,
     struct virtio_blk_config *blkcfg)
@@ -659,59 +656,6 @@ vtblk_resize_disk(struct vtblk_softc *sc, uint64_t new_capacity)
 	}
 }
 
-static void
-vtblk_set_write_cache(struct vtblk_softc *sc, int wc)
-{
-
-	/* Set either writeback (1) or writethrough (0) mode. */
-	virtio_write_dev_config_1(sc->vtblk_dev,
-	    offsetof(struct virtio_blk_config, writeback), wc);
-}
-
-static int
-vtblk_write_cache_enabled(struct vtblk_softc *sc,
-    struct virtio_blk_config *blkcfg)
-{
-	int wc;
-
-	if (sc->vtblk_flags & VTBLK_FLAG_WC_CONFIG) {
-		wc = vtblk_tunable_int(sc, "writecache_mode",
-		    vtblk_writecache_mode);
-		if (wc >= 0 && wc < VTBLK_CACHE_MAX)
-			vtblk_set_write_cache(sc, wc);
-		else
-			wc = blkcfg->writeback;
-	} else
-		wc = virtio_with_feature(sc->vtblk_dev, VIRTIO_BLK_F_WCE);
-
-	return (wc);
-}
-
-static int
-vtblk_write_cache_sysctl(SYSCTL_HANDLER_ARGS)
-{
-	struct vtblk_softc *sc;
-	int wc, error;
-
-	sc = oidp->oid_arg1;
-	wc = sc->vtblk_write_cache;
-
-	error = sysctl_handle_int(oidp, &wc, 0, req);
-	if (error || req->newptr == NULL)
-		return (error);
-	if ((sc->vtblk_flags & VTBLK_FLAG_WC_CONFIG) == 0)
-		return (EPERM);
-	if (wc < 0 || wc >= VTBLK_CACHE_MAX)
-		return (EINVAL);
-
-	VTBLK_LOCK(sc);
-	sc->vtblk_write_cache = wc;
-	vtblk_set_write_cache(sc, sc->vtblk_write_cache);
-	VTBLK_UNLOCK(sc);
-
-	return (0);
-}
-
 static void
 vtblk_alloc_disk(struct vtblk_softc *sc, struct virtio_blk_config *blkcfg)
 {
@@ -728,7 +672,8 @@ vtblk_alloc_disk(struct vtblk_softc *sc, struct virtio_blk_config *blkcfg)
 	dp->d_name = VTBLK_DISK_NAME;
 	dp->d_unit = device_get_unit(dev);
 	dp->d_drv1 = sc;
-	dp->d_flags = DISKFLAG_CANFLUSHCACHE | DISKFLAG_UNMAPPED_BIO;
+	dp->d_flags = DISKFLAG_CANFLUSHCACHE | DISKFLAG_UNMAPPED_BIO |
+	    DISKFLAG_DIRECT_COMPLETION;
 	dp->d_hba_vendor = virtio_get_vendor(dev);
 	dp->d_hba_device = virtio_get_device(dev);
 	dp->d_hba_subvendor = virtio_get_subvendor(dev);
@@ -789,11 +734,7 @@ vtblk_create_disk(struct vtblk_softc *sc)
 
 	dp = sc->vtblk_disk;
 
-	/*
-	 * Retrieving the identification string must be done after
-	 * the virtqueue interrupt is setup otherwise it will hang.
-	 */
-	vtblk_get_ident(sc);
+	vtblk_ident(sc);
 
 	device_printf(sc->vtblk_dev, "%juMB (%ju %u byte sectors)\n",
 	    (uintmax_t) dp->d_mediasize >> 20,
@@ -804,57 +745,107 @@ vtblk_create_disk(struct vtblk_softc *sc)
 }
 
 static int
-vtblk_quiesce(struct vtblk_softc *sc)
+vtblk_request_prealloc(struct vtblk_softc *sc)
 {
-	int error;
+	struct vtblk_request *req;
+	int i, nreqs;
 
-	error = 0;
+	nreqs = virtqueue_size(sc->vtblk_vq);
 
-	VTBLK_LOCK_ASSERT(sc);
+	/*
+	 * Preallocate sufficient requests to keep the virtqueue full. Each
+	 * request consumes VTBLK_MIN_SEGMENTS or more descriptors so reduce
+	 * the number allocated when indirect descriptors are not available.
+	 */
+	if ((sc->vtblk_flags & VTBLK_FLAG_INDIRECT) == 0)
+		nreqs /= VTBLK_MIN_SEGMENTS;
 
-	while (!virtqueue_empty(sc->vtblk_vq)) {
-		if (mtx_sleep(&sc->vtblk_vq, VTBLK_MTX(sc), PRIBIO, "vtblkq",
-		    VTBLK_QUIESCE_TIMEOUT) == EWOULDBLOCK) {
-			error = EBUSY;
-			break;
-		}
+	for (i = 0; i < nreqs; i++) {
+		req = malloc(sizeof(struct vtblk_request), M_DEVBUF, M_NOWAIT);
+		if (req == NULL)
+			return (ENOMEM);
+
+		MPASS(sglist_count(&req->vbr_hdr, sizeof(req->vbr_hdr)) == 1);
+		MPASS(sglist_count(&req->vbr_ack, sizeof(req->vbr_ack)) == 1);
+
+		sc->vtblk_request_count++;
+		vtblk_request_enqueue(sc, req);
 	}
 
-	return (error);
+	return (0);
 }
 
 static void
-vtblk_startio(struct vtblk_softc *sc)
+vtblk_request_free(struct vtblk_softc *sc)
 {
-	struct virtqueue *vq;
 	struct vtblk_request *req;
-	int enq;
 
-	vq = sc->vtblk_vq;
-	enq = 0;
+	MPASS(TAILQ_EMPTY(&sc->vtblk_req_ready));
 
-	VTBLK_LOCK_ASSERT(sc);
-
-	while (!virtqueue_full(vq)) {
-		if ((req = vtblk_dequeue_ready(sc)) == NULL)
-			req = vtblk_bio_request(sc);
-		if (req == NULL)
-			break;
-
-		if (vtblk_execute_request(sc, req) != 0) {
-			vtblk_enqueue_ready(sc, req);
-			break;
-		}
-
-		enq++;
+	while ((req = vtblk_request_dequeue(sc)) != NULL) {
+		sc->vtblk_request_count--;
+		free(req, M_DEVBUF);
 	}
 
-	if (enq > 0)
-		virtqueue_notify(vq);
+	KASSERT(sc->vtblk_request_count == 0,
+	    ("%s: leaked %d requests", __func__, sc->vtblk_request_count));
 }
 
 static struct vtblk_request *
-vtblk_bio_request(struct vtblk_softc *sc)
+vtblk_request_dequeue(struct vtblk_softc *sc)
+{
+	struct vtblk_request *req;
+
+	req = TAILQ_FIRST(&sc->vtblk_req_free);
+	if (req != NULL) {
+		TAILQ_REMOVE(&sc->vtblk_req_free, req, vbr_link);
+		bzero(req, sizeof(struct vtblk_request));
+	}
+
+	return (req);
+}
+
+static void
+vtblk_request_enqueue(struct vtblk_softc *sc, struct vtblk_request *req)
+{
+
+	TAILQ_INSERT_HEAD(&sc->vtblk_req_free, req, vbr_link);
+}
+
+static struct vtblk_request *
+vtblk_request_next_ready(struct vtblk_softc *sc)
+{
+	struct vtblk_request *req;
+
+	req = TAILQ_FIRST(&sc->vtblk_req_ready);
+	if (req != NULL)
+		TAILQ_REMOVE(&sc->vtblk_req_ready, req, vbr_link);
+
+	return (req);
+}
+
+static void
+vtblk_request_requeue_ready(struct vtblk_softc *sc, struct vtblk_request *req)
+{
+
+	/* NOTE: Currently, there will be at most one request in the queue. */
+	TAILQ_INSERT_HEAD(&sc->vtblk_req_ready, req, vbr_link);
+}
+
+static struct vtblk_request *
+vtblk_request_next(struct vtblk_softc *sc)
+{
+	struct vtblk_request *req;
+
+	req = vtblk_request_next_ready(sc);
+	if (req != NULL)
+		return (req);
+
+	return (vtblk_request_bio(sc));
+}
+
+static struct vtblk_request *
+vtblk_request_bio(struct vtblk_softc *sc)
 {
 	struct bio_queue_head *bioq;
 	struct vtblk_request *req;
@@ -865,7 +856,7 @@ vtblk_bio_request(struct vtblk_softc *sc)
 	if (bioq_first(bioq) == NULL)
 		return (NULL);
 
-	req = vtblk_dequeue_request(sc);
+	req = vtblk_request_dequeue(sc);
 	if (req == NULL)
 		return (NULL);
 
@@ -890,11 +881,14 @@ vtblk_bio_request(struct vtblk_softc *sc)
 		panic("%s: bio with unhandled cmd: %d", __func__, bp->bio_cmd);
 	}
 
+	if (bp->bio_flags & BIO_ORDERED)
+		req->vbr_hdr.type |= VIRTIO_BLK_T_BARRIER;
+
 	return (req);
 }
 
 static int
-vtblk_execute_request(struct vtblk_softc *sc, struct vtblk_request *req)
+vtblk_request_execute(struct vtblk_softc *sc, struct vtblk_request *req)
 {
 	struct virtqueue *vq;
 	struct sglist *sg;
@@ -907,26 +901,20 @@ vtblk_execute_request(struct vtblk_softc *sc, struct vtblk_request *req)
 	ordered = 0;
 	writable = 0;
 
-	VTBLK_LOCK_ASSERT(sc);
-
 	/*
-	 * Wait until the ordered request completes before
-	 * executing subsequent requests.
+	 * Some hosts (such as bhyve) do not implement the barrier feature,
+	 * so we emulate it in the driver by allowing the barrier request
+	 * to be the only one in flight.
 	 */
-	if (sc->vtblk_req_ordered != NULL)
-		return (EBUSY);
-
-	if (bp->bio_flags & BIO_ORDERED) {
-		if ((sc->vtblk_flags & VTBLK_FLAG_BARRIER) == 0) {
-			/*
-			 * This request will be executed once all
-			 * the in-flight requests are completed.
-			 */
+	if ((sc->vtblk_flags & VTBLK_FLAG_BARRIER) == 0) {
+		if (sc->vtblk_req_ordered != NULL)
+			return (EBUSY);
+		if (bp->bio_flags & BIO_ORDERED) {
 			if (!virtqueue_empty(vq))
 				return (EBUSY);
 			ordered = 1;
-		} else
-			req->vbr_hdr.type |= VIRTIO_BLK_T_BARRIER;
+			req->vbr_hdr.type &= ~VIRTIO_BLK_T_BARRIER;
+		}
 	}
 
 	sglist_reset(sg);
@@ -935,7 +923,7 @@ vtblk_execute_request(struct vtblk_softc *sc, struct vtblk_request *req)
 	if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
 		error = sglist_append_bio(sg, bp);
 		if (error || sg->sg_nseg == sg->sg_maxseg) {
-			panic("%s: data buffer too big bio:%p error:%d",
+			panic("%s: bio %p data buffer too big %d",
 			    __func__, bp, error);
 		}
 
@@ -955,44 +943,156 @@ vtblk_execute_request(struct vtblk_softc *sc, struct vtblk_request *req)
 	return (error);
 }
 
-static void
-vtblk_vq_intr(void *xsc)
+static int
+vtblk_request_error(struct vtblk_request *req)
 {
-	struct vtblk_softc *sc;
-	struct virtqueue *vq;
+	int error;
 
-	sc = xsc;
-	vq = sc->vtblk_vq;
-
-again:
-	VTBLK_LOCK(sc);
-	if (sc->vtblk_flags & VTBLK_FLAG_DETACH) {
-		VTBLK_UNLOCK(sc);
-		return;
+	switch (req->vbr_ack) {
+	case VIRTIO_BLK_S_OK:
+		error = 0;
+		break;
+	case VIRTIO_BLK_S_UNSUPP:
+		error = ENOTSUP;
+		break;
+	default:
+		error = EIO;
+		break;
 	}
 
-	vtblk_finish_completed(sc);
-
-	if ((sc->vtblk_flags & VTBLK_FLAG_SUSPEND) == 0)
-		vtblk_startio(sc);
-	else
-		wakeup(&sc->vtblk_vq);
-
-	if (virtqueue_enable_intr(vq) != 0) {
-		virtqueue_disable_intr(vq);
-		VTBLK_UNLOCK(sc);
-		goto again;
-	}
-
-	VTBLK_UNLOCK(sc);
+	return (error);
 }
 
 static void
-vtblk_stop(struct vtblk_softc *sc)
+vtblk_queue_completed(struct vtblk_softc *sc, struct bio_queue *queue)
+{
+	struct vtblk_request *req;
+	struct bio *bp;
+
+	while ((req = virtqueue_dequeue(sc->vtblk_vq, NULL)) != NULL) {
+		if (sc->vtblk_req_ordered != NULL) {
+			MPASS(sc->vtblk_req_ordered == req);
+			sc->vtblk_req_ordered = NULL;
+		}
+
+		bp = req->vbr_bp;
+		bp->bio_error = vtblk_request_error(req);
+		TAILQ_INSERT_TAIL(queue, bp, bio_queue);
+
+		vtblk_request_enqueue(sc, req);
+	}
+}
+
+static void
+vtblk_done_completed(struct vtblk_softc *sc, struct bio_queue *queue)
+{
+	struct bio *bp, *tmp;
+
+	TAILQ_FOREACH_SAFE(bp, queue, bio_queue, tmp) {
+		if (bp->bio_error != 0)
+			disk_err(bp, "hard error", -1, 1);
+		vtblk_bio_done(sc, bp, bp->bio_error);
+	}
+}
+
+static void
+vtblk_drain_vq(struct vtblk_softc *sc, int skip_done)
+{
+	struct virtqueue *vq;
+	struct vtblk_request *req;
+	int last;
+
+	vq = sc->vtblk_vq;
+	last = 0;
+
+	while ((req = virtqueue_drain(vq, &last)) != NULL) {
+		if (!skip_done)
+			vtblk_bio_done(sc, req->vbr_bp, ENXIO);
+
+		vtblk_request_enqueue(sc, req);
+	}
+
+	sc->vtblk_req_ordered = NULL;
+	KASSERT(virtqueue_empty(vq), ("virtqueue not empty"));
+}
+
+static void
+vtblk_drain(struct vtblk_softc *sc)
+{
+	struct bio_queue queue;
+	struct bio_queue_head *bioq;
+	struct vtblk_request *req;
+	struct bio *bp;
+
+	bioq = &sc->vtblk_bioq;
+	TAILQ_INIT(&queue);
+
+	if (sc->vtblk_vq != NULL) {
+		vtblk_queue_completed(sc, &queue);
+		vtblk_done_completed(sc, &queue);
+
+		vtblk_drain_vq(sc, 0);
+	}
+
+	while ((req = vtblk_request_next_ready(sc)) != NULL) {
+		vtblk_bio_done(sc, req->vbr_bp, ENXIO);
+		vtblk_request_enqueue(sc, req);
+	}
+
+	while (bioq_first(bioq) != NULL) {
+		bp = bioq_takefirst(bioq);
+		vtblk_bio_done(sc, bp, ENXIO);
+	}
+
+	vtblk_request_free(sc);
+}
+
+static void
+vtblk_startio(struct vtblk_softc *sc)
+{
+	struct virtqueue *vq;
+	struct vtblk_request *req;
+	int enq;
+
+	VTBLK_LOCK_ASSERT(sc);
+	vq = sc->vtblk_vq;
+	enq = 0;
+
+	if (sc->vtblk_flags & VTBLK_FLAG_SUSPEND)
+		return;
+
+	while (!virtqueue_full(vq)) {
+		req = vtblk_request_next(sc);
+		if (req == NULL)
+			break;
+
+		if (vtblk_request_execute(sc, req) != 0) {
+			vtblk_request_requeue_ready(sc, req);
+			break;
+		}
+
+		enq++;
+	}
+
+	if (enq > 0)
+		virtqueue_notify(vq);
+}
+
+static void
+vtblk_bio_done(struct vtblk_softc *sc, struct bio *bp, int error)
 {
 
-	virtqueue_disable_intr(sc->vtblk_vq);
-	virtio_stop(sc->vtblk_dev);
+	/* Because of GEOM direct dispatch, we cannot hold any locks. */
+	if (sc != NULL)
+		VTBLK_LOCK_ASSERT_NOTOWNED(sc);
+
+	if (error) {
+		bp->bio_resid = bp->bio_bcount;
+		bp->bio_error = error;
+		bp->bio_flags |= BIO_ERROR;
+	}
+
+	biodone(bp);
 }
 
 #define VTBLK_GET_CONFIG(_dev, _feature, _field, _cfg)			\
@@ -1027,7 +1127,7 @@ vtblk_read_config(struct vtblk_softc *sc, struct virtio_blk_config *blkcfg)
 #undef VTBLK_GET_CONFIG
 
 static void
-vtblk_get_ident(struct vtblk_softc *sc)
+vtblk_ident(struct vtblk_softc *sc)
 {
 	struct bio buf;
 	struct disk *dp;
@@ -1040,7 +1140,7 @@ vtblk_get_ident(struct vtblk_softc *sc)
 	if (vtblk_tunable_int(sc, "no_ident", vtblk_no_ident) != 0)
 		return;
 
-	req = vtblk_dequeue_request(sc);
+	req = vtblk_request_dequeue(sc);
 	if (req == NULL)
 		return;
 
@@ -1060,7 +1160,7 @@ vtblk_get_ident(struct vtblk_softc *sc)
 	error = vtblk_poll_request(sc, req);
 	VTBLK_UNLOCK(sc);
 
-	vtblk_enqueue_request(sc, req);
+	vtblk_request_enqueue(sc, req);
 
 	if (error) {
 		device_printf(sc->vtblk_dev,
@@ -1068,8 +1168,95 @@ vtblk_get_ident(struct vtblk_softc *sc)
 	}
 }
 
+static int
+vtblk_poll_request(struct vtblk_softc *sc, struct vtblk_request *req)
+{
+	struct virtqueue *vq;
+	int error;
+
+	vq = sc->vtblk_vq;
+
+	if (!virtqueue_empty(vq))
+		return (EBUSY);
+
+	error = vtblk_request_execute(sc, req);
+	if (error)
+		return (error);
+
+	virtqueue_notify(vq);
+	virtqueue_poll(vq, NULL);
+
+	error = vtblk_request_error(req);
+	if (error && bootverbose) {
+		device_printf(sc->vtblk_dev,
+		    "%s: IO error: %d\n", __func__, error);
+	}
+
+	return (error);
+}
+
+static int
+vtblk_quiesce(struct vtblk_softc *sc)
+{
+	int error;
+
+	VTBLK_LOCK_ASSERT(sc);
+	error = 0;
+
+	while (!virtqueue_empty(sc->vtblk_vq)) {
+		if (mtx_sleep(&sc->vtblk_vq, VTBLK_MTX(sc), PRIBIO, "vtblkq",
+		    VTBLK_QUIESCE_TIMEOUT) == EWOULDBLOCK) {
+			error = EBUSY;
+			break;
+		}
+	}
+
+	return (error);
+}
+
 static void
-vtblk_prepare_dump(struct vtblk_softc *sc)
+vtblk_vq_intr(void *xsc)
+{
+	struct vtblk_softc *sc;
+	struct virtqueue *vq;
+	struct bio_queue queue;
+
+	sc = xsc;
+	vq = sc->vtblk_vq;
+	TAILQ_INIT(&queue);
+
+	VTBLK_LOCK(sc);
+
+again:
+	if (sc->vtblk_flags & VTBLK_FLAG_DETACH)
+		goto out;
+
+	vtblk_queue_completed(sc, &queue);
+	vtblk_startio(sc);
+
+	if (virtqueue_enable_intr(vq) != 0) {
+		virtqueue_disable_intr(vq);
+		goto again;
+	}
+
+	if (sc->vtblk_flags & VTBLK_FLAG_SUSPEND)
+		wakeup(&sc->vtblk_vq);
+
+out:
+	VTBLK_UNLOCK(sc);
+	vtblk_done_completed(sc, &queue);
+}
+
+static void
+vtblk_stop(struct vtblk_softc *sc)
+{
+
+	virtqueue_disable_intr(sc->vtblk_vq);
+	virtio_stop(sc->vtblk_dev);
+}
+
+static void
+vtblk_dump_prepare(struct vtblk_softc *sc)
 {
 	device_t dev;
 	struct virtqueue *vq;
@@ -1097,7 +1284,7 @@ vtblk_prepare_dump(struct vtblk_softc *sc)
 }
 
 static int
-vtblk_write_dump(struct vtblk_softc *sc, void *virtual, off_t offset,
+vtblk_dump_write(struct vtblk_softc *sc, void *virtual, off_t offset,
     size_t length)
 {
 	struct bio buf;
@@ -1120,7 +1307,7 @@ vtblk_write_dump(struct vtblk_softc *sc, void *virtual, off_t offset,
 }
 
 static int
-vtblk_flush_dump(struct vtblk_softc *sc)
+vtblk_dump_flush(struct vtblk_softc *sc)
 {
 	struct bio buf;
 	struct vtblk_request *req;
@@ -1139,241 +1326,59 @@ vtblk_flush_dump(struct vtblk_softc *sc)
 	return (vtblk_poll_request(sc, req));
 }
 
-static int
-vtblk_poll_request(struct vtblk_softc *sc, struct vtblk_request *req)
+static void
+vtblk_set_write_cache(struct vtblk_softc *sc, int wc)
 {
-	struct virtqueue *vq;
-	int error;
 
-	vq = sc->vtblk_vq;
+	/* Set either writeback (1) or writethrough (0) mode. */
+	virtio_write_dev_config_1(sc->vtblk_dev,
+	    offsetof(struct virtio_blk_config, writeback), wc);
+}
 
-	if (!virtqueue_empty(vq))
-		return (EBUSY);
+static int
+vtblk_write_cache_enabled(struct vtblk_softc *sc,
+    struct virtio_blk_config *blkcfg)
+{
+	int wc;
 
-	error = vtblk_execute_request(sc, req);
-	if (error)
+	if (sc->vtblk_flags & VTBLK_FLAG_WC_CONFIG) {
+		wc = vtblk_tunable_int(sc, "writecache_mode",
+		    vtblk_writecache_mode);
+		if (wc >= 0 && wc < VTBLK_CACHE_MAX)
+			vtblk_set_write_cache(sc, wc);
+		else
+			wc = blkcfg->writeback;
+	} else
+		wc = virtio_with_feature(sc->vtblk_dev, VIRTIO_BLK_F_WCE);
+
+	return (wc);
+}
+
+static int
+vtblk_write_cache_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct vtblk_softc *sc;
+	int wc, error;
+
+	sc = oidp->oid_arg1;
+	wc = sc->vtblk_write_cache;
+
+	error = sysctl_handle_int(oidp, &wc, 0, req);
+	if (error || req->newptr == NULL)
 		return (error);
+	if ((sc->vtblk_flags & VTBLK_FLAG_WC_CONFIG) == 0)
+		return (EPERM);
+	if (wc < 0 || wc >= VTBLK_CACHE_MAX)
+		return (EINVAL);
 
-	virtqueue_notify(vq);
-	virtqueue_poll(vq, NULL);
-
-	error = vtblk_request_error(req);
-	if (error && bootverbose) {
-		device_printf(sc->vtblk_dev,
-		    "%s: IO error: %d\n", __func__, error);
-	}
-
-	return (error);
-}
-
-static void
-vtblk_finish_completed(struct vtblk_softc *sc)
-{
-	struct vtblk_request *req;
-	struct bio *bp;
-	int error;
-
-	while ((req = virtqueue_dequeue(sc->vtblk_vq, NULL)) != NULL) {
-		bp = req->vbr_bp;
-
-		if (sc->vtblk_req_ordered != NULL) {
-			/* This should be the only outstanding request. */
-			MPASS(sc->vtblk_req_ordered == req);
-			sc->vtblk_req_ordered = NULL;
-		}
-
-		error = vtblk_request_error(req);
-		if (error)
-			disk_err(bp, "hard error", -1, 1);
-
-		vtblk_finish_bio(bp, error);
-		vtblk_enqueue_request(sc, req);
-	}
-}
-
-static void
-vtblk_drain_vq(struct vtblk_softc *sc, int skip_done)
-{
-	struct virtqueue *vq;
-	struct vtblk_request *req;
-	int last;
-
-	vq = sc->vtblk_vq;
-	last = 0;
-
-	while ((req = virtqueue_drain(vq, &last)) != NULL) {
-		if (!skip_done)
-			vtblk_finish_bio(req->vbr_bp, ENXIO);
-
-		vtblk_enqueue_request(sc, req);
-	}
-
-	sc->vtblk_req_ordered = NULL;
-	KASSERT(virtqueue_empty(vq), ("virtqueue not empty"));
-}
-
-static void
-vtblk_drain(struct vtblk_softc *sc)
-{
-	struct bio_queue_head *bioq;
-	struct vtblk_request *req;
-	struct bio *bp;
-
-	bioq = &sc->vtblk_bioq;
-
-	if (sc->vtblk_vq != NULL) {
-		vtblk_finish_completed(sc);
-		vtblk_drain_vq(sc, 0);
-	}
-
-	while ((req = vtblk_dequeue_ready(sc)) != NULL) {
-		vtblk_finish_bio(req->vbr_bp, ENXIO);
-		vtblk_enqueue_request(sc, req);
-	}
-
-	while (bioq_first(bioq) != NULL) {
-		bp = bioq_takefirst(bioq);
-		vtblk_finish_bio(bp, ENXIO);
-	}
-
-	vtblk_free_requests(sc);
-}
-
-#ifdef INVARIANTS
-static void
-vtblk_request_invariants(struct vtblk_request *req)
-{
-	int hdr_nsegs, ack_nsegs;
-
-	hdr_nsegs = sglist_count(&req->vbr_hdr, sizeof(req->vbr_hdr));
-	ack_nsegs = sglist_count(&req->vbr_ack, sizeof(req->vbr_ack));
-
-	KASSERT(hdr_nsegs == 1, ("request header crossed page boundary"));
-	KASSERT(ack_nsegs == 1, ("request ack crossed page boundary"));
-}
-#endif
-
-static int
-vtblk_alloc_requests(struct vtblk_softc *sc)
-{
-	struct vtblk_request *req;
-	int i, nreqs;
-
-	nreqs = virtqueue_size(sc->vtblk_vq);
-
-	/*
-	 * Preallocate sufficient requests to keep the virtqueue full. Each
-	 * request consumes VTBLK_MIN_SEGMENTS or more descriptors so reduce
-	 * the number allocated when indirect descriptors are not available.
-	 */
-	if ((sc->vtblk_flags & VTBLK_FLAG_INDIRECT) == 0)
-		nreqs /= VTBLK_MIN_SEGMENTS;
-
-	for (i = 0; i < nreqs; i++) {
-		req = malloc(sizeof(struct vtblk_request), M_DEVBUF, M_NOWAIT);
-		if (req == NULL)
-			return (ENOMEM);
-
-#ifdef INVARIANTS
-		vtblk_request_invariants(req);
-#endif
-
-		sc->vtblk_request_count++;
-		vtblk_enqueue_request(sc, req);
-	}
+	VTBLK_LOCK(sc);
+	sc->vtblk_write_cache = wc;
+	vtblk_set_write_cache(sc, sc->vtblk_write_cache);
+	VTBLK_UNLOCK(sc);
 
 	return (0);
 }
 
-static void
-vtblk_free_requests(struct vtblk_softc *sc)
-{
-	struct vtblk_request *req;
-
-	KASSERT(TAILQ_EMPTY(&sc->vtblk_req_ready),
-	    ("%s: ready requests left on queue", __func__));
-
-	while ((req = vtblk_dequeue_request(sc)) != NULL) {
-		sc->vtblk_request_count--;
-		free(req, M_DEVBUF);
-	}
-
-	KASSERT(sc->vtblk_request_count == 0,
-	    ("%s: leaked %d requests", __func__, sc->vtblk_request_count));
-}
-
-static struct vtblk_request *
-vtblk_dequeue_request(struct vtblk_softc *sc)
-{
-	struct vtblk_request *req;
-
-	req = TAILQ_FIRST(&sc->vtblk_req_free);
-	if (req != NULL)
-		TAILQ_REMOVE(&sc->vtblk_req_free, req, vbr_link);
-
-	return (req);
-}
-
-static void
-vtblk_enqueue_request(struct vtblk_softc *sc, struct vtblk_request *req)
-{
-
-	bzero(req, sizeof(struct vtblk_request));
-	TAILQ_INSERT_HEAD(&sc->vtblk_req_free, req, vbr_link);
-}
-
-static struct vtblk_request *
-vtblk_dequeue_ready(struct vtblk_softc *sc)
-{
-	struct vtblk_request *req;
-
-	req = TAILQ_FIRST(&sc->vtblk_req_ready);
-	if (req != NULL)
-		TAILQ_REMOVE(&sc->vtblk_req_ready, req, vbr_link);
-
-	return (req);
-}
-
-static void
-vtblk_enqueue_ready(struct vtblk_softc *sc, struct vtblk_request *req)
-{
-
-	TAILQ_INSERT_HEAD(&sc->vtblk_req_ready, req, vbr_link);
-}
-
-static int
-vtblk_request_error(struct vtblk_request *req)
-{
-	int error;
-
-	switch (req->vbr_ack) {
-	case VIRTIO_BLK_S_OK:
-		error = 0;
-		break;
-	case VIRTIO_BLK_S_UNSUPP:
-		error = ENOTSUP;
-		break;
-	default:
-		error = EIO;
-		break;
-	}
-
-	return (error);
-}
-
-static void
-vtblk_finish_bio(struct bio *bp, int error)
-{
-
-	if (error) {
-		bp->bio_resid = bp->bio_bcount;
-		bp->bio_error = error;
-		bp->bio_flags |= BIO_ERROR;
-	}
-
-	biodone(bp);
-}
-
 static void
 vtblk_setup_sysctl(struct vtblk_softc *sc)
 {
diff --git a/sys/dev/virtio/network/if_vtnet.c b/sys/dev/virtio/network/if_vtnet.c
index 83cb2d79fe25..9fba9bdabe0b 100644
--- a/sys/dev/virtio/network/if_vtnet.c
+++ b/sys/dev/virtio/network/if_vtnet.c
@@ -1701,7 +1701,7 @@ vtnet_rxq_input(struct vtnet_rxq *rxq, struct mbuf *m,
 	}
 
 	m->m_pkthdr.flowid = rxq->vtnrx_id;
-	m->m_flags |= M_FLOWID;
+	M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
 
 	/*
 	 * BMV: FreeBSD does not have the UNNECESSARY and PARTIAL checksum
@@ -2347,7 +2347,8 @@ vtnet_txq_mq_start(struct ifnet *ifp, struct mbuf *m)
 	sc = ifp->if_softc;
 	npairs = sc->vtnet_act_vq_pairs;
 
-	if (m->m_flags & M_FLOWID)
+	/* check if flowid is set */
+	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
 		i = m->m_pkthdr.flowid % npairs;
 	else
 		i = curcpu % npairs;
diff --git a/sys/dev/vmware/vmxnet3/if_vmx.c b/sys/dev/vmware/vmxnet3/if_vmx.c
index 1d8c12e2fc9b..5faf716acf4d 100644
--- a/sys/dev/vmware/vmxnet3/if_vmx.c
+++ b/sys/dev/vmware/vmxnet3/if_vmx.c
@@ -2059,7 +2059,7 @@ vmxnet3_rxq_input(struct vmxnet3_rxqueue *rxq,
 	}
 #else
 	m->m_pkthdr.flowid = rxq->vxrxq_id;
-	m->m_flags |= M_FLOWID;
+	M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
 #endif
 
 	if (!rxcd->no_csum)
@@ -3002,7 +3002,8 @@ vmxnet3_txq_mq_start(struct ifnet *ifp, struct mbuf *m)
 	sc = ifp->if_softc;
 	ntxq = sc->vmx_ntxqueues;
 
-	if (m->m_flags & M_FLOWID)
+	/* check if flowid is set */
+	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
 		i = m->m_pkthdr.flowid % ntxq;
 	else
 		i = curcpu % ntxq;
diff --git a/sys/dev/vxge/vxge.c b/sys/dev/vxge/vxge.c
index b89ba6cca51e..9a3cab654f95 100644
--- a/sys/dev/vxge/vxge.c
+++ b/sys/dev/vxge/vxge.c
@@ -660,7 +660,7 @@ vxge_mq_send(ifnet_t ifp, mbuf_t m_head)
 
 	if (vdev->config.tx_steering) {
 		i = vxge_vpath_get(vdev, m_head);
-	} else if ((m_head->m_flags & M_FLOWID) != 0) {
+	} else if (M_HASHTYPE_GET(m_head) != M_HASHTYPE_NONE) {
 		i = m_head->m_pkthdr.flowid % vdev->no_of_vpath;
 	}
 
@@ -1070,7 +1070,7 @@ vxge_rx_compl(vxge_hal_vpath_h vpath_handle, vxge_hal_rxd_h rxdh,
 		vxge_rx_checksum(ext_info, mbuf_up);
 
 #if __FreeBSD_version >= 800000
-		mbuf_up->m_flags |= M_FLOWID;
+		M_HASHTYPE_SET(mbuf_up, M_HASHTYPE_OPAQUE);
 		mbuf_up->m_pkthdr.flowid = vpath->vp_index;
 #endif
 		/* Post-Read sync for buffers */
diff --git a/sys/kern/subr_taskqueue.c b/sys/kern/subr_taskqueue.c
index 3a3dbc44c04f..f82e2457b012 100644
--- a/sys/kern/subr_taskqueue.c
+++ b/sys/kern/subr_taskqueue.c
@@ -661,11 +661,11 @@ taskqueue_thread_enqueue(void *context)
 
 TASKQUEUE_DEFINE(swi, taskqueue_swi_enqueue, NULL,
 		 swi_add(NULL, "task queue", taskqueue_swi_run, NULL, SWI_TQ,
-		     INTR_MPSAFE, &taskqueue_ih)); 
+		     INTR_MPSAFE, &taskqueue_ih));
 
 TASKQUEUE_DEFINE(swi_giant, taskqueue_swi_giant_enqueue, NULL,
 		 swi_add(NULL, "Giant taskq", taskqueue_swi_giant_run,
-		     NULL, SWI_TQ_GIANT, 0, &taskqueue_giant_ih)); 
+		     NULL, SWI_TQ_GIANT, 0, &taskqueue_giant_ih));
 
 TASKQUEUE_DEFINE_THREAD(thread);
 
diff --git a/sys/kern/uipc_debug.c b/sys/kern/uipc_debug.c
index 0f233ecebd69..c3081a497ae6 100644
--- a/sys/kern/uipc_debug.c
+++ b/sys/kern/uipc_debug.c
@@ -401,7 +401,8 @@ db_print_sockbuf(struct sockbuf *sb, const char *sockbufname, int indent)
 	db_printf("sb_sndptroff: %u\n", sb->sb_sndptroff);
 
 	db_print_indent(indent);
-	db_printf("sb_cc: %u   ", sb->sb_cc);
+	db_printf("sb_acc: %u   ", sb->sb_acc);
+	db_printf("sb_ccc: %u   ", sb->sb_ccc);
 	db_printf("sb_hiwat: %u   ", sb->sb_hiwat);
 	db_printf("sb_mbcnt: %u   ", sb->sb_mbcnt);
 	db_printf("sb_mbmax: %u\n", sb->sb_mbmax);
diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c
index 709cc0eb0569..9eda77c0f2d8 100644
--- a/sys/kern/uipc_domain.c
+++ b/sys/kern/uipc_domain.c
@@ -152,6 +152,7 @@ protosw_init(struct protosw *pr)
 	DEFAULT(pu->pru_sosend, sosend_generic);
 	DEFAULT(pu->pru_soreceive, soreceive_generic);
 	DEFAULT(pu->pru_sopoll, sopoll_generic);
+	DEFAULT(pu->pru_ready, pru_ready_notsupp);
 #undef DEFAULT
 	if (pr->pr_init)
 		(*pr->pr_init)();
diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c
index 323426898d09..3880456bddf7 100644
--- a/sys/kern/uipc_mbuf.c
+++ b/sys/kern/uipc_mbuf.c
@@ -388,7 +388,7 @@ mb_dupcl(struct mbuf *n, struct mbuf *m)
  * cleaned too.
  */
 void
-m_demote(struct mbuf *m0, int all)
+m_demote(struct mbuf *m0, int all, int flags)
 {
 	struct mbuf *m;
 
@@ -400,7 +400,7 @@ m_demote(struct mbuf *m0, int all)
 			m->m_flags &= ~M_PKTHDR;
 			bzero(&m->m_pkthdr, sizeof(struct pkthdr));
 		}
-		m->m_flags = m->m_flags & (M_EXT|M_RDONLY|M_NOFREE);
+		m->m_flags = m->m_flags & (M_EXT | M_RDONLY | M_NOFREE | flags);
 	}
 }
 
@@ -997,7 +997,7 @@ m_catpkt(struct mbuf *m, struct mbuf *n)
 	M_ASSERTPKTHDR(n);
 
 	m->m_pkthdr.len += n->m_pkthdr.len;
-	m_demote(n, 1);
+	m_demote(n, 1, 0);
 
 	m_cat(m, n);
 }
diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c
index 01e48b55aac0..537f9c867bf8 100644
--- a/sys/kern/uipc_sockbuf.c
+++ b/sys/kern/uipc_sockbuf.c
@@ -68,6 +68,123 @@ static	u_long sb_efficiency = 8;	/* parameter for sbreserve() */
 static struct mbuf	*sbcut_internal(struct sockbuf *sb, int len);
 static void	sbflush_internal(struct sockbuf *sb);
 
+/*
+ * Mark ready "count" mbufs starting with "m".
+ */
+int
+sbready(struct sockbuf *sb, struct mbuf *m, int count)
+{
+	u_int blocker;
+
+	SOCKBUF_LOCK_ASSERT(sb);
+	KASSERT(sb->sb_fnrdy != NULL, ("%s: sb %p NULL fnrdy", __func__, sb));
+
+	blocker = (sb->sb_fnrdy == m) ? M_BLOCKED : 0;
+
+	for (int i = 0; i < count; i++, m = m->m_next) {
+		KASSERT(m->m_flags & M_NOTREADY,
+		    ("%s: m %p !M_NOTREADY", __func__, m));
+		m->m_flags &= ~(M_NOTREADY | blocker);
+		if (blocker)
+			sb->sb_acc += m->m_len;
+	}
+
+	if (!blocker)
+		return (EINPROGRESS);
+
+	/* This one was blocking all the queue. */
+	for (; m && (m->m_flags & M_NOTREADY) == 0; m = m->m_next) {
+		KASSERT(m->m_flags & M_BLOCKED,
+		    ("%s: m %p !M_BLOCKED", __func__, m));
+		m->m_flags &= ~M_BLOCKED;
+		sb->sb_acc += m->m_len;
+	}
+
+	sb->sb_fnrdy = m;
+
+	return (0);
+}
+
+/*
+ * Adjust sockbuf state reflecting allocation of m.
+ */
+void
+sballoc(struct sockbuf *sb, struct mbuf *m)
+{
+
+	SOCKBUF_LOCK_ASSERT(sb);
+
+	sb->sb_ccc += m->m_len;
+
+	if (sb->sb_fnrdy == NULL) {
+		if (m->m_flags & M_NOTREADY)
+			sb->sb_fnrdy = m;
+		else
+			sb->sb_acc += m->m_len;
+	} else
+		m->m_flags |= M_BLOCKED;
+
+	if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA)
+		sb->sb_ctl += m->m_len;
+
+	sb->sb_mbcnt += MSIZE;
+	sb->sb_mcnt += 1;
+
+	if (m->m_flags & M_EXT) {
+		sb->sb_mbcnt += m->m_ext.ext_size;
+		sb->sb_ccnt += 1;
+	}
+}
+
+/*
+ * Adjust sockbuf state reflecting freeing of m.
+ */
+void
+sbfree(struct sockbuf *sb, struct mbuf *m)
+{
+
+#if 0	/* XXX: not yet: soclose() call path comes here w/o lock. */
+	SOCKBUF_LOCK_ASSERT(sb);
+#endif
+
+	sb->sb_ccc -= m->m_len;
+
+	if (!(m->m_flags & M_NOTAVAIL))
+		sb->sb_acc -= m->m_len;
+
+	if (m == sb->sb_fnrdy) {
+		struct mbuf *n;
+
+		KASSERT(m->m_flags & M_NOTREADY,
+		    ("%s: m %p !M_NOTREADY", __func__, m));
+
+		n = m->m_next;
+		while (n != NULL && !(n->m_flags & M_NOTREADY)) {
+			n->m_flags &= ~M_BLOCKED;
+			sb->sb_acc += n->m_len;
+			n = n->m_next;
+		}
+		sb->sb_fnrdy = n;
+	}
+
+	if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA)
+		sb->sb_ctl -= m->m_len;
+
+	sb->sb_mbcnt -= MSIZE;
+	sb->sb_mcnt -= 1;
+	if (m->m_flags & M_EXT) {
+		sb->sb_mbcnt -= m->m_ext.ext_size;
+		sb->sb_ccnt -= 1;
+	}
+
+	if (sb->sb_sndptr == m) {
+		sb->sb_sndptr = NULL;
+		sb->sb_sndptroff = 0;
+	}
+	if (sb->sb_sndptroff != 0)
+		sb->sb_sndptroff -= m->m_len;
+}
+
 /*
  * Socantsendmore indicates that no more data will be sent on the socket; it
  * would normally be applied to a socket when the user informs the system
@@ -127,7 +244,7 @@ sbwait(struct sockbuf *sb)
 	SOCKBUF_LOCK_ASSERT(sb);
 
 	sb->sb_flags |= SB_WAIT;
-	return (msleep_sbt(&sb->sb_cc, &sb->sb_mtx,
+	return (msleep_sbt(&sb->sb_acc, &sb->sb_mtx,
 	    (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, "sbwait",
 	    sb->sb_timeo, 0, 0));
 }
@@ -184,7 +301,7 @@ sowakeup(struct socket *so, struct sockbuf *sb)
 		sb->sb_flags &= ~SB_SEL;
 	if (sb->sb_flags & SB_WAIT) {
 		sb->sb_flags &= ~SB_WAIT;
-		wakeup(&sb->sb_cc);
+		wakeup(&sb->sb_acc);
 	}
 	KNOTE_LOCKED(&sb->sb_sel.si_note, 0);
 	if (sb->sb_upcall != NULL) {
@@ -519,7 +636,7 @@ sbappend(struct sockbuf *sb, struct mbuf *m)
  * that is, a stream protocol (such as TCP).
  */
 void
-sbappendstream_locked(struct sockbuf *sb, struct mbuf *m)
+sbappendstream_locked(struct sockbuf *sb, struct mbuf *m, int flags)
 {
 	SOCKBUF_LOCK_ASSERT(sb);
 
@@ -529,8 +646,8 @@ sbappendstream_locked(struct sockbuf *sb, struct mbuf *m)
 	SBLASTMBUFCHK(sb);
 
 	/* Remove all packet headers and mbuf tags to get a pure data chain. */
-	m_demote(m, 1);
-	
+	m_demote(m, 1, flags & PRUS_NOTREADY ? M_NOTREADY : 0);
+
 	sbcompress(sb, m, sb->sb_mbtail);
 
 	sb->sb_lastrecord = sb->sb_mb;
@@ -543,38 +660,63 @@ sbappendstream_locked(struct sockbuf *sb, struct mbuf *m)
  * that is, a stream protocol (such as TCP).
  */
 void
-sbappendstream(struct sockbuf *sb, struct mbuf *m)
+sbappendstream(struct sockbuf *sb, struct mbuf *m, int flags)
 {
 
 	SOCKBUF_LOCK(sb);
-	sbappendstream_locked(sb, m);
+	sbappendstream_locked(sb, m, flags);
 	SOCKBUF_UNLOCK(sb);
 }
 
 #ifdef SOCKBUF_DEBUG
 void
-sbcheck(struct sockbuf *sb)
+sbcheck(struct sockbuf *sb, const char *file, int line)
 {
-	struct mbuf *m;
-	struct mbuf *n = 0;
-	u_long len = 0, mbcnt = 0;
+	struct mbuf *m, *n, *fnrdy;
+	u_long acc, ccc, mbcnt;
 
 	SOCKBUF_LOCK_ASSERT(sb);
 
+	acc = ccc = mbcnt = 0;
+	fnrdy = NULL;
+
 	for (m = sb->sb_mb; m; m = n) {
 	    n = m->m_nextpkt;
 	    for (; m; m = m->m_next) {
-		len += m->m_len;
+		if (m->m_len == 0) {
+			printf("sb %p empty mbuf %p\n", sb, m);
+			goto fail;
+		}
+		if ((m->m_flags & M_NOTREADY) && fnrdy == NULL) {
+			if (m != sb->sb_fnrdy) {
+				printf("sb %p: fnrdy %p != m %p\n",
+				    sb, sb->sb_fnrdy, m);
+				goto fail;
+			}
+			fnrdy = m;
+		}
+		if (fnrdy) {
+			if (!(m->m_flags & M_NOTAVAIL)) {
+				printf("sb %p: fnrdy %p, m %p is avail\n",
+				    sb, sb->sb_fnrdy, m);
+				goto fail;
+			}
+		} else
+			acc += m->m_len;
+		ccc += m->m_len;
 		mbcnt += MSIZE;
 		if (m->m_flags & M_EXT) /*XXX*/ /* pretty sure this is bogus */
 			mbcnt += m->m_ext.ext_size;
 	    }
 	}
-	if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
-		printf("cc %ld != %u || mbcnt %ld != %u\n", len, sb->sb_cc,
-		    mbcnt, sb->sb_mbcnt);
-		panic("sbcheck");
+	if (acc != sb->sb_acc || ccc != sb->sb_ccc || mbcnt != sb->sb_mbcnt) {
+		printf("acc %ld/%u ccc %ld/%u mbcnt %ld/%u\n",
+		    acc, sb->sb_acc, ccc, sb->sb_ccc, mbcnt, sb->sb_mbcnt);
+		goto fail;
 	}
+	return;
+fail:
+	panic("%s from %s:%u", __func__, file, line);
 }
 #endif
 
@@ -770,8 +912,8 @@ sbappendcontrol(struct sockbuf *sb, struct mbuf *m0, struct mbuf *control)
  *
  * (2) The mbuf may be coalesced -- i.e., data in the mbuf may be copied into
  *     an mbuf already in the socket buffer.  This can occur if an
- *     appropriate mbuf exists, there is room, and no merging of data types
- *     will occur.
+ *     appropriate mbuf exists, there is room, both mbufs are not marked as
+ *     not ready, and no merging of data types will occur.
  *
  * (3) The mbuf may be appended to the end of the existing mbuf chain.
  *
@@ -800,13 +942,17 @@ sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n)
 		if (n && (n->m_flags & M_EOR) == 0 &&
 		    M_WRITABLE(n) &&
 		    ((sb->sb_flags & SB_NOCOALESCE) == 0) &&
+		    !(m->m_flags & M_NOTREADY) &&
+		    !(n->m_flags & M_NOTREADY) &&
 		    m->m_len <= MCLBYTES / 4 && /* XXX: Don't copy too much */
 		    m->m_len <= M_TRAILINGSPACE(n) &&
 		    n->m_type == m->m_type) {
 			bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len,
 			    (unsigned)m->m_len);
 			n->m_len += m->m_len;
-			sb->sb_cc += m->m_len;
+			sb->sb_ccc += m->m_len;
+			if (sb->sb_fnrdy == NULL)
+				sb->sb_acc += m->m_len;
 			if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA)
 				/* XXX: Probably don't need.*/
 				sb->sb_ctl += m->m_len;
@@ -843,13 +989,13 @@ sbflush_internal(struct sockbuf *sb)
 		 * Don't call sbcut(sb, 0) if the leading mbuf is non-empty:
 		 * we would loop forever. Panic instead.
 		 */
-		if (!sb->sb_cc && (sb->sb_mb == NULL || sb->sb_mb->m_len))
+		if (sb->sb_ccc == 0 && (sb->sb_mb == NULL || sb->sb_mb->m_len))
 			break;
-		m_freem(sbcut_internal(sb, (int)sb->sb_cc));
+		m_freem(sbcut_internal(sb, (int)sb->sb_ccc));
 	}
-	if (sb->sb_cc || sb->sb_mb || sb->sb_mbcnt)
-		panic("sbflush_internal: cc %u || mb %p || mbcnt %u",
-		    sb->sb_cc, (void *)sb->sb_mb, sb->sb_mbcnt);
+	KASSERT(sb->sb_ccc == 0 && sb->sb_mb == 0 && sb->sb_mbcnt == 0,
+	    ("%s: ccc %u mb %p mbcnt %u", __func__,
+	    sb->sb_ccc, (void *)sb->sb_mb, sb->sb_mbcnt));
 }
 
 void
@@ -875,7 +1021,7 @@ sbflush(struct sockbuf *sb)
 static struct mbuf *
 sbcut_internal(struct sockbuf *sb, int len)
 {
-	struct mbuf *m, *n, *next, *mfree;
+	struct mbuf *m, *next, *mfree;
 
 	next = (m = sb->sb_mb) ? m->m_nextpkt : 0;
 	mfree = NULL;
@@ -887,9 +1033,12 @@ sbcut_internal(struct sockbuf *sb, int len)
 			next = m->m_nextpkt;
 		}
 		if (m->m_len > len) {
+			KASSERT(!(m->m_flags & M_NOTAVAIL),
+			    ("%s: m %p M_NOTAVAIL", __func__, m));
 			m->m_len -= len;
 			m->m_data += len;
-			sb->sb_cc -= len;
+			sb->sb_ccc -= len;
+			sb->sb_acc -= len;
 			if (sb->sb_sndptroff != 0)
 				sb->sb_sndptroff -= len;
 			if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA)
@@ -898,10 +1047,20 @@ sbcut_internal(struct sockbuf *sb, int len)
 		}
 		len -= m->m_len;
 		sbfree(sb, m);
-		n = m->m_next;
-		m->m_next = mfree;
-		mfree = m;
-		m = n;
+		/*
+		 * Do not put M_NOTREADY buffers to the free list, they
+		 * are referenced from outside.
+		 */
+		if (m->m_flags & M_NOTREADY)
+			m = m->m_next;
+		else {
+			struct mbuf *n;
+
+			n = m->m_next;
+			m->m_next = mfree;
+			mfree = m;
+			m = n;
+		}
 	}
 	if (m) {
 		sb->sb_mb = m;
@@ -968,8 +1127,8 @@ sbsndptr(struct sockbuf *sb, u_int off, u_int len, u_int *moff)
 	struct mbuf *m, *ret;
 
 	KASSERT(sb->sb_mb != NULL, ("%s: sb_mb is NULL", __func__));
-	KASSERT(off + len <= sb->sb_cc, ("%s: beyond sb", __func__));
-	KASSERT(sb->sb_sndptroff <= sb->sb_cc, ("%s: sndptroff broken", __func__));
+	KASSERT(off + len <= sb->sb_acc, ("%s: beyond sb", __func__));
+	KASSERT(sb->sb_sndptroff <= sb->sb_acc, ("%s: sndptroff broken", __func__));
 
 	/*
 	 * Is off below stored offset? Happens on retransmits.
@@ -1118,7 +1277,7 @@ void
 sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb)
 {
 
-	xsb->sb_cc = sb->sb_cc;
+	xsb->sb_cc = sb->sb_ccc;
 	xsb->sb_hiwat = sb->sb_hiwat;
 	xsb->sb_mbcnt = sb->sb_mbcnt;
 	xsb->sb_mcnt = sb->sb_mcnt;	
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 240421f694b2..b2091ea28417 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1706,7 +1706,8 @@ dontblock:
 	 */
 	moff = 0;
 	offset = 0;
-	while (m != NULL && uio->uio_resid > 0 && error == 0) {
+	while (m != NULL && !(m->m_flags & M_NOTAVAIL) && uio->uio_resid > 0
+	    && error == 0) {
 		/*
 		 * If the type of mbuf has changed since the last mbuf
 		 * examined ('type'), end the receive operation.
@@ -2044,6 +2045,8 @@ deliver:
 			for (m = sb->sb_mb;
 			     m != NULL && m->m_len <= len;
 			     m = m->m_next) {
+				KASSERT(!(m->m_flags & M_NOTAVAIL),
+				    ("%s: m %p not available", __func__, m));
 				len -= m->m_len;
 				uio->uio_resid -= m->m_len;
 				sbfree(sb, m);
@@ -3175,6 +3178,13 @@ pru_send_notsupp(struct socket *so, int flags, struct mbuf *m,
 	return EOPNOTSUPP;
 }
 
+int
+pru_ready_notsupp(struct socket *so, struct mbuf *m, int count)
+{
+
+	return (EOPNOTSUPP);
+}
+
 /*
  * This isn't really a ``null'' operation, but it's the default one and
  * doesn't do anything destructive.
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index 00fd8099c2e4..a540cc0dfa85 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -1047,6 +1047,32 @@ release:
 	return (error);
 }
 
+static int
+uipc_ready(struct socket *so, struct mbuf *m, int count)
+{
+	struct unpcb *unp, *unp2;
+	struct socket *so2;
+	int error;
+
+	unp = sotounpcb(so);
+
+	UNP_LINK_RLOCK();
+	unp2 = unp->unp_conn;
+	UNP_PCB_LOCK(unp2);
+	so2 = unp2->unp_socket;
+
+	SOCKBUF_LOCK(&so2->so_rcv);
+	if ((error = sbready(&so2->so_rcv, m, count)) == 0)
+		sorwakeup_locked(so2);
+	else
+		SOCKBUF_UNLOCK(&so2->so_rcv);
+
+	UNP_PCB_UNLOCK(unp2);
+	UNP_LINK_RUNLOCK();
+
+	return (error);
+}
+
 static int
 uipc_sense(struct socket *so, struct stat *sb)
 {
@@ -1161,6 +1187,7 @@ static struct pr_usrreqs uipc_usrreqs_stream = {
 	.pru_peeraddr =		uipc_peeraddr,
 	.pru_rcvd =		uipc_rcvd,
 	.pru_send =		uipc_send,
+	.pru_ready =		uipc_ready,
 	.pru_sense =		uipc_sense,
 	.pru_shutdown =		uipc_shutdown,
 	.pru_sockaddr =		uipc_sockaddr,
diff --git a/sys/net/flowtable.c b/sys/net/flowtable.c
index fe6a52cd3c10..0d584fea3581 100644
--- a/sys/net/flowtable.c
+++ b/sys/net/flowtable.c
@@ -688,8 +688,8 @@ flowtable_lookup(sa_family_t sa, struct mbuf *m, struct route *ro)
 	if (fle == NULL)
 		return (EHOSTUNREACH);
 
-	if (!(m->m_flags & M_FLOWID)) {
-		m->m_flags |= M_FLOWID;
+	if (M_HASHTYPE_GET(m) == M_HASHTYPE_NONE) {
+		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
 		m->m_pkthdr.flowid = fle->f_hash;
 	}
 
diff --git a/sys/net/ieee8023ad_lacp.c b/sys/net/ieee8023ad_lacp.c
index 106df68e807a..75f6366e7888 100644
--- a/sys/net/ieee8023ad_lacp.c
+++ b/sys/net/ieee8023ad_lacp.c
@@ -835,7 +835,8 @@ lacp_select_tx_port(struct lagg_softc *sc, struct mbuf *m)
 		return (NULL);
 	}
 
-	if ((sc->sc_opts & LAGG_OPT_USE_FLOWID) && (m->m_flags & M_FLOWID))
+	if ((sc->sc_opts & LAGG_OPT_USE_FLOWID) &&
+	    M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
 		hash = m->m_pkthdr.flowid >> sc->flowid_shift;
 	else
 		hash = lagg_hashmbuf(sc, m, lsc->lsc_hashkey);
diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c
index 5c8b2e1d2bdf..45315b6b3b55 100644
--- a/sys/net/if_lagg.c
+++ b/sys/net/if_lagg.c
@@ -247,14 +247,14 @@ SYSCTL_INT(_net_link_lagg, OID_AUTO, failover_rx_all, CTLFLAG_RW | CTLFLAG_VNET,
     &VNET_NAME(lagg_failover_rx_all), 0,
     "Accept input from any interface in a failover lagg");
 
-/* Default value for using M_FLOWID */
+/* Default value for using flowid */
 static VNET_DEFINE(int, def_use_flowid) = 1;
 #define	V_def_use_flowid	VNET(def_use_flowid)
 SYSCTL_INT(_net_link_lagg, OID_AUTO, default_use_flowid, CTLFLAG_RWTUN,
     &VNET_NAME(def_use_flowid), 0,
     "Default setting for using flow id for load sharing");
 
-/* Default value for using M_FLOWID */
+/* Default value for flowid shift */
 static VNET_DEFINE(int, def_flowid_shift) = 16;
 #define	V_def_flowid_shift	VNET(def_flowid_shift)
 SYSCTL_INT(_net_link_lagg, OID_AUTO, default_flowid_shift, CTLFLAG_RWTUN,
@@ -2148,7 +2148,8 @@ lagg_lb_start(struct lagg_softc *sc, struct mbuf *m)
 	struct lagg_port *lp = NULL;
 	uint32_t p = 0;
 
-	if ((sc->sc_opts & LAGG_OPT_USE_FLOWID) && (m->m_flags & M_FLOWID))
+	if ((sc->sc_opts & LAGG_OPT_USE_FLOWID) &&
+	    M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
 		p = m->m_pkthdr.flowid >> sc->flowid_shift;
 	else
 		p = lagg_hashmbuf(sc, m, lb->lb_key);
diff --git a/sys/net/if_lagg.h b/sys/net/if_lagg.h
index e86ed06fcca7..8d6decd3c069 100644
--- a/sys/net/if_lagg.h
+++ b/sys/net/if_lagg.h
@@ -143,9 +143,9 @@ struct lagg_reqopts {
 
 	int			ro_opts;		/* Option bitmap */
 #define	LAGG_OPT_NONE			0x00
-#define	LAGG_OPT_USE_FLOWID		0x01		/* use M_FLOWID */
+#define	LAGG_OPT_USE_FLOWID		0x01		/* enable use of flowid */
 /* Pseudo flags which are used in ro_opts but not stored into sc_opts. */
-#define	LAGG_OPT_FLOWIDSHIFT		0x02		/* Set flowid */
+#define	LAGG_OPT_FLOWIDSHIFT		0x02		/* set flowid shift */
 #define	LAGG_OPT_FLOWIDSHIFT_MASK	0x1f		/* flowid is uint32_t */
 #define	LAGG_OPT_LACP_STRICT		0x10		/* LACP strict mode */
 #define	LAGG_OPT_LACP_TXTEST		0x20		/* LACP debug: txtest */
diff --git a/sys/net/if_vxlan.c b/sys/net/if_vxlan.c
index 5badf00051fd..59c76ebf4f1b 100644
--- a/sys/net/if_vxlan.c
+++ b/sys/net/if_vxlan.c
@@ -2236,6 +2236,7 @@ vxlan_pick_source_port(struct vxlan_softc *sc, struct mbuf *m)
 
 	range = sc->vxl_max_port - sc->vxl_min_port + 1;
 
+	/* check if flowid is set and not opaque */
 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE &&
 	    M_HASHTYPE_GET(m) != M_HASHTYPE_OPAQUE)
 		hash = m->m_pkthdr.flowid;
diff --git a/sys/net/netisr.c b/sys/net/netisr.c
index 049bbf192b53..178c3cbd1479 100644
--- a/sys/net/netisr.c
+++ b/sys/net/netisr.c
@@ -682,12 +682,13 @@ netisr_select_cpuid(struct netisr_proto *npp, u_int dispatch_policy,
 	}
 
 	if (policy == NETISR_POLICY_FLOW) {
-		if (!(m->m_flags & M_FLOWID) && npp->np_m2flow != NULL) {
+		if (M_HASHTYPE_GET(m) == M_HASHTYPE_NONE &&
+		    npp->np_m2flow != NULL) {
 			m = npp->np_m2flow(m, source);
 			if (m == NULL)
 				return (NULL);
 		}
-		if (m->m_flags & M_FLOWID) {
+		if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
 			*cpuidp =
 			    netisr_default_flow2cpu(m->m_pkthdr.flowid);
 			return (m);
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index 04ed0b0bdf83..606795a69bb0 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -530,8 +530,8 @@ short	inp_so_options(const struct inpcb *inp);
 #define	INP_ONESBCAST		0x02000000 /* send all-ones broadcast */
 #define	INP_DROPPED		0x04000000 /* protocol drop flag */
 #define	INP_SOCKREF		0x08000000 /* strong socket reference */
-#define	INP_SW_FLOWID           0x10000000 /* software generated flow id */
-#define	INP_HW_FLOWID           0x20000000 /* hardware generated flow id */
+#define	INP_RESERVED_0          0x10000000 /* reserved field */
+#define	INP_RESERVED_1          0x20000000 /* reserved field */
 #define	IN6P_RFC2292		0x40000000 /* used RFC2292 API on the socket */
 #define	IN6P_MTU		0x80000000 /* receive path MTU */
 
diff --git a/sys/netinet/in_rss.c b/sys/netinet/in_rss.c
index 7a548c2a8d2e..5d4f3c0dd37f 100644
--- a/sys/netinet/in_rss.c
+++ b/sys/netinet/in_rss.c
@@ -568,6 +568,8 @@ rss_mbuf_software_hash_v4(const struct mbuf *m, int dir, uint32_t *hashval,
 	const struct ip *ip;
 	const struct tcphdr *th;
 	const struct udphdr *uh;
+	uint32_t flowid;
+	uint32_t flowtype;
 	uint8_t proto;
 	int iphlen;
 	int is_frag = 0;
@@ -617,12 +619,10 @@ rss_mbuf_software_hash_v4(const struct mbuf *m, int dir, uint32_t *hashval,
 	 * then we shouldn't just "trust" the 2-tuple hash.  We need
 	 * a 4-tuple hash.
 	 */
-	if (m->m_flags & M_FLOWID) {
-		uint32_t flowid, flowtype;
-
-		flowid = m->m_pkthdr.flowid;
-		flowtype = M_HASHTYPE_GET(m);
+	flowid = m->m_pkthdr.flowid;
+	flowtype = M_HASHTYPE_GET(m);
 
+	if (flowtype != M_HASHTYPE_NONE) {
 		switch (proto) {
 		case IPPROTO_UDP:
 			if ((rss_gethashconfig_local() & RSS_HASHTYPE_RSS_UDP_IPV4) &&
@@ -743,7 +743,6 @@ rss_soft_m2cpuid(struct mbuf *m, uintptr_t source, u_int *cpuid)
 		/* hash was done; update */
 		m->m_pkthdr.flowid = hash_val;
 		M_HASHTYPE_SET(m, hash_type);
-		m->m_flags |= M_FLOWID;
 		*cpuid = rss_hash2cpuid(m->m_pkthdr.flowid, M_HASHTYPE_GET(m));
 	} else { /* ret < 0 */
 		/* no hash was done */
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index d0229b2dccd1..7b8127e90dae 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -1196,7 +1196,6 @@ found:
 	if (rss_mbuf_software_hash_v4(m, 0, &rss_hash, &rss_type) == 0) {
 		m->m_pkthdr.flowid = rss_hash;
 		M_HASHTYPE_SET(m, rss_type);
-		m->m_flags |= M_FLOWID;
 	}
 
 	/*
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 5d791e57e99f..611c53c7e941 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -147,11 +147,9 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
 	if (inp != NULL) {
 		INP_LOCK_ASSERT(inp);
 		M_SETFIB(m, inp->inp_inc.inc_fibnum);
-		if (((flags & IP_NODEFAULTFLOWID) == 0) &&
-		    inp->inp_flags & (INP_HW_FLOWID|INP_SW_FLOWID)) {
+		if ((flags & IP_NODEFAULTFLOWID) == 0) {
 			m->m_pkthdr.flowid = inp->inp_flowid;
 			M_HASHTYPE_SET(m, inp->inp_flowtype);
-			m->m_flags |= M_FLOWID;
 		}
 	}
 
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 2065bb4fdae4..97ca01338e83 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -70,14 +70,14 @@ sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc)
 
 	/*
 	 * This is really set wrong with respect to a 1-2-m socket. Since
-	 * the sb_cc is the count that everyone as put up. When we re-write
+	 * the sb_ccc is the count that everyone as put up. When we re-write
 	 * sctp_soreceive then we will fix this so that ONLY this
 	 * associations data is taken into account.
 	 */
 	if (stcb->sctp_socket == NULL)
 		return (calc);
 
-	if (stcb->asoc.sb_cc == 0 &&
+	if (stcb->asoc.sb_ccc == 0 &&
 	    asoc->size_on_reasm_queue == 0 &&
 	    asoc->size_on_all_streams == 0) {
 		/* Full rwnd granted */
@@ -1363,7 +1363,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
 		 * When we have NO room in the rwnd we check to make sure
 		 * the reader is doing its job...
 		 */
-		if (stcb->sctp_socket->so_rcv.sb_cc) {
+		if (stcb->sctp_socket->so_rcv.sb_ccc) {
 			/* some to read, wake-up */
 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
 			struct socket *so;
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 62de260179ad..52ac81e92fb7 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -1032,7 +1032,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp SCTP_UNUSED,
 	if (stcb->sctp_socket) {
 		if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
 		    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
-			stcb->sctp_socket->so_snd.sb_cc = 0;
+			stcb->sctp_socket->so_snd.sb_ccc = 0;
 		}
 		sctp_ulp_notify(SCTP_NOTIFY_ASSOC_DOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED);
 	}
diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h
index 558d4e18357c..69ecf40655dd 100644
--- a/sys/netinet/sctp_os_bsd.h
+++ b/sys/netinet/sctp_os_bsd.h
@@ -399,7 +399,7 @@ typedef struct callout sctp_os_timer_t;
 #define SCTP_SOWAKEUP(so)	wakeup(&(so)->so_timeo)
 /* clear the socket buffer state */
 #define SCTP_SB_CLEAR(sb)	\
-	(sb).sb_cc = 0;		\
+	(sb).sb_ccc = 0;		\
 	(sb).sb_mb = NULL;	\
 	(sb).sb_mbcnt = 0;
 
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index a122325a28e6..3139be08091f 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -7250,7 +7250,7 @@ one_more_time:
 			if ((stcb->sctp_socket != NULL) && \
 			    ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
 			    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
-				atomic_subtract_int(&stcb->sctp_socket->so_snd.sb_cc, sp->length);
+				atomic_subtract_int(&stcb->sctp_socket->so_snd.sb_ccc, sp->length);
 			}
 			if (sp->data) {
 				sctp_m_freem(sp->data);
@@ -11532,7 +11532,7 @@ jump_out:
 		drp->current_onq = htonl(asoc->size_on_reasm_queue +
 		    asoc->size_on_all_streams +
 		    asoc->my_rwnd_control_len +
-		    stcb->sctp_socket->so_rcv.sb_cc);
+		    stcb->sctp_socket->so_rcv.sb_ccc);
 	} else {
 		/*-
 		 * If my rwnd is 0, possibly from mbuf depletion as well as
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 2fa99b9e6243..72c3f042f7de 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -3397,7 +3397,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
 			if ((asoc->asoc.size_on_reasm_queue > 0) ||
 			    (asoc->asoc.control_pdapi) ||
 			    (asoc->asoc.size_on_all_streams > 0) ||
-			    (so && (so->so_rcv.sb_cc > 0))) {
+			    (so && (so->so_rcv.sb_ccc > 0))) {
 				/* Left with Data unread */
 				struct mbuf *op_err;
 
@@ -3625,7 +3625,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
 		TAILQ_REMOVE(&inp->read_queue, sq, next);
 		sctp_free_remote_addr(sq->whoFrom);
 		if (so)
-			so->so_rcv.sb_cc -= sq->length;
+			so->so_rcv.sb_ccc -= sq->length;
 		if (sq->data) {
 			sctp_m_freem(sq->data);
 			sq->data = NULL;
@@ -4853,7 +4853,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
 			inp->sctp_flags |= SCTP_PCB_FLAGS_WAS_CONNECTED;
 			if (so) {
 				SOCK_LOCK(so);
-				if (so->so_rcv.sb_cc == 0) {
+				if (so->so_rcv.sb_ccc == 0) {
 					so->so_state &= ~(SS_ISCONNECTING |
 					    SS_ISDISCONNECTING |
 					    SS_ISCONFIRMING |
diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h
index c9183b1d8207..25416283f916 100644
--- a/sys/netinet/sctp_pcb.h
+++ b/sys/netinet/sctp_pcb.h
@@ -369,7 +369,7 @@ struct sctp_inpcb {
 	}     ip_inp;
 
 
-	/* Socket buffer lock protects read_queue and of course sb_cc */
+	/* Socket buffer lock protects read_queue and of course sb_ccc */
 	struct sctp_readhead read_queue;
 
 	              LIST_ENTRY(sctp_inpcb) sctp_list;	/* lists all endpoints */
diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h
index 3f6d935ba173..127068145525 100644
--- a/sys/netinet/sctp_structs.h
+++ b/sys/netinet/sctp_structs.h
@@ -990,7 +990,7 @@ struct sctp_association {
 
 	uint32_t total_output_queue_size;
 
-	uint32_t sb_cc;		/* shadow of sb_cc */
+	uint32_t sb_ccc;		/* shadow of sb_ccc */
 	uint32_t sb_send_resv;	/* amount reserved on a send */
 	uint32_t my_rwnd_control_len;	/* shadow of sb_mbcnt used for rwnd
 					 * control */
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index e1ad178135e0..9dc7cdced64a 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -586,7 +586,7 @@ sctp_must_try_again:
 	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
 	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
 		if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
-		    (so->so_rcv.sb_cc > 0)) {
+		    (so->so_rcv.sb_ccc > 0)) {
 #ifdef SCTP_LOG_CLOSING
 			sctp_log_closing(inp, NULL, 13);
 #endif
@@ -751,7 +751,7 @@ sctp_disconnect(struct socket *so)
 			}
 			if (((so->so_options & SO_LINGER) &&
 			    (so->so_linger == 0)) ||
-			    (so->so_rcv.sb_cc > 0)) {
+			    (so->so_rcv.sb_ccc > 0)) {
 				if (SCTP_GET_STATE(asoc) !=
 				    SCTP_STATE_COOKIE_WAIT) {
 					/* Left with Data unread */
@@ -916,7 +916,7 @@ sctp_flush(struct socket *so, int how)
 		inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ;
 		SCTP_INP_READ_UNLOCK(inp);
 		SCTP_INP_WUNLOCK(inp);
-		so->so_rcv.sb_cc = 0;
+		so->so_rcv.sb_ccc = 0;
 		so->so_rcv.sb_mbcnt = 0;
 		so->so_rcv.sb_mb = NULL;
 	}
@@ -925,7 +925,7 @@ sctp_flush(struct socket *so, int how)
 		 * First make sure the sb will be happy, we don't use these
 		 * except maybe the count
 		 */
-		so->so_snd.sb_cc = 0;
+		so->so_snd.sb_ccc = 0;
 		so->so_snd.sb_mbcnt = 0;
 		so->so_snd.sb_mb = NULL;
 
diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h
index 31d93dd21bd9..bab8a7709dd5 100644
--- a/sys/netinet/sctp_var.h
+++ b/sys/netinet/sctp_var.h
@@ -82,9 +82,9 @@ extern struct pr_usrreqs sctp_usrreqs;
 
 #define sctp_maxspace(sb) (max((sb)->sb_hiwat,SCTP_MINIMAL_RWND))
 
-#define	sctp_sbspace(asoc, sb) ((long) ((sctp_maxspace(sb) > (asoc)->sb_cc) ? (sctp_maxspace(sb) - (asoc)->sb_cc) : 0))
+#define	sctp_sbspace(asoc, sb) ((long) ((sctp_maxspace(sb) > (asoc)->sb_ccc) ? (sctp_maxspace(sb) - (asoc)->sb_ccc) : 0))
 
-#define	sctp_sbspace_failedmsgs(sb) ((long) ((sctp_maxspace(sb) > (sb)->sb_cc) ? (sctp_maxspace(sb) - (sb)->sb_cc) : 0))
+#define	sctp_sbspace_failedmsgs(sb) ((long) ((sctp_maxspace(sb) > (sb)->sb_ccc) ? (sctp_maxspace(sb) - (sb)->sb_ccc) : 0))
 
 #define sctp_sbspace_sub(a,b) ((a > b) ? (a - b) : 0)
 
@@ -195,10 +195,10 @@ extern struct pr_usrreqs sctp_usrreqs;
 }
 
 #define sctp_sbfree(ctl, stcb, sb, m) { \
-	SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_cc, SCTP_BUF_LEN((m))); \
+	SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_ccc, SCTP_BUF_LEN((m))); \
 	SCTP_SAVE_ATOMIC_DECREMENT(&(sb)->sb_mbcnt, MSIZE); \
 	if (((ctl)->do_not_ref_stcb == 0) && stcb) {\
-		SCTP_SAVE_ATOMIC_DECREMENT(&(stcb)->asoc.sb_cc, SCTP_BUF_LEN((m))); \
+		SCTP_SAVE_ATOMIC_DECREMENT(&(stcb)->asoc.sb_ccc, SCTP_BUF_LEN((m))); \
 		SCTP_SAVE_ATOMIC_DECREMENT(&(stcb)->asoc.my_rwnd_control_len, MSIZE); \
 	} \
 	if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \
@@ -207,10 +207,10 @@ extern struct pr_usrreqs sctp_usrreqs;
 }
 
 #define sctp_sballoc(stcb, sb, m) { \
-	atomic_add_int(&(sb)->sb_cc,SCTP_BUF_LEN((m))); \
+	atomic_add_int(&(sb)->sb_ccc,SCTP_BUF_LEN((m))); \
 	atomic_add_int(&(sb)->sb_mbcnt, MSIZE); \
 	if (stcb) { \
-		atomic_add_int(&(stcb)->asoc.sb_cc,SCTP_BUF_LEN((m))); \
+		atomic_add_int(&(stcb)->asoc.sb_ccc,SCTP_BUF_LEN((m))); \
 		atomic_add_int(&(stcb)->asoc.my_rwnd_control_len, MSIZE); \
 	} \
 	if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 1e87a17b2cba..e0e0670d5a50 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -67,9 +67,9 @@ sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr)
 	struct sctp_cwnd_log sctp_clog;
 
 	sctp_clog.x.sb.stcb = stcb;
-	sctp_clog.x.sb.so_sbcc = sb->sb_cc;
+	sctp_clog.x.sb.so_sbcc = sb->sb_ccc;
 	if (stcb)
-		sctp_clog.x.sb.stcb_sbcc = stcb->asoc.sb_cc;
+		sctp_clog.x.sb.stcb_sbcc = stcb->asoc.sb_ccc;
 	else
 		sctp_clog.x.sb.stcb_sbcc = 0;
 	sctp_clog.x.sb.incr = incr;
@@ -4363,7 +4363,7 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
 {
 	/*
 	 * Here we must place the control on the end of the socket read
-	 * queue AND increment sb_cc so that select will work properly on
+	 * queue AND increment sb_ccc so that select will work properly on
 	 * read.
 	 */
 	struct mbuf *m, *prev = NULL;
@@ -4489,7 +4489,7 @@ sctp_append_to_readq(struct sctp_inpcb *inp,
 	 * the reassembly queue.
 	 * 
 	 * If PDAPI this means we need to add m to the end of the data.
-	 * Increase the length in the control AND increment the sb_cc.
+	 * Increase the length in the control AND increment the sb_ccc.
 	 * Otherwise sb is NULL and all we need to do is put it at the end
 	 * of the mbuf chain.
 	 */
@@ -4701,10 +4701,10 @@ sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc,
 
 	if (stcb->sctp_socket && (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) ||
 	    ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)))) {
-		if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) {
-			stcb->sctp_socket->so_snd.sb_cc -= tp1->book_size;
+		if (stcb->sctp_socket->so_snd.sb_ccc >= tp1->book_size) {
+			stcb->sctp_socket->so_snd.sb_ccc -= tp1->book_size;
 		} else {
-			stcb->sctp_socket->so_snd.sb_cc = 0;
+			stcb->sctp_socket->so_snd.sb_ccc = 0;
 
 		}
 	}
@@ -5254,11 +5254,11 @@ sctp_sorecvmsg(struct socket *so,
 	in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
 		sctp_misc_ints(SCTP_SORECV_ENTER,
-		    rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, uio->uio_resid);
+		    rwnd_req, in_eeor_mode, so->so_rcv.sb_ccc, uio->uio_resid);
 	}
 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
 		sctp_misc_ints(SCTP_SORECV_ENTERPL,
-		    rwnd_req, block_allowed, so->so_rcv.sb_cc, uio->uio_resid);
+		    rwnd_req, block_allowed, so->so_rcv.sb_ccc, uio->uio_resid);
 	}
 	error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0));
 	if (error) {
@@ -5277,23 +5277,23 @@ restart_nosblocks:
 	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
 		goto out;
 	}
-	if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) {
+	if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && (so->so_rcv.sb_ccc == 0)) {
 		if (so->so_error) {
 			error = so->so_error;
 			if ((in_flags & MSG_PEEK) == 0)
 				so->so_error = 0;
 			goto out;
 		} else {
-			if (so->so_rcv.sb_cc == 0) {
+			if (so->so_rcv.sb_ccc == 0) {
 				/* indicate EOF */
 				error = 0;
 				goto out;
 			}
 		}
 	}
-	if ((so->so_rcv.sb_cc <= held_length) && block_allowed) {
+	if ((so->so_rcv.sb_ccc <= held_length) && block_allowed) {
 		/* we need to wait for data */
-		if ((so->so_rcv.sb_cc == 0) &&
+		if ((so->so_rcv.sb_ccc == 0) &&
 		    ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
 		    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
 			if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) {
@@ -5329,7 +5329,7 @@ restart_nosblocks:
 		}
 		held_length = 0;
 		goto restart_nosblocks;
-	} else if (so->so_rcv.sb_cc == 0) {
+	} else if (so->so_rcv.sb_ccc == 0) {
 		if (so->so_error) {
 			error = so->so_error;
 			if ((in_flags & MSG_PEEK) == 0)
@@ -5386,11 +5386,11 @@ restart_nosblocks:
 			SCTP_INP_READ_LOCK(inp);
 		}
 		control = TAILQ_FIRST(&inp->read_queue);
-		if ((control == NULL) && (so->so_rcv.sb_cc != 0)) {
+		if ((control == NULL) && (so->so_rcv.sb_ccc != 0)) {
 #ifdef INVARIANTS
 			panic("Huh, its non zero and nothing on control?");
 #endif
-			so->so_rcv.sb_cc = 0;
+			so->so_rcv.sb_ccc = 0;
 		}
 		SCTP_INP_READ_UNLOCK(inp);
 		hold_rlock = 0;
@@ -5511,11 +5511,11 @@ restart_nosblocks:
 		}
 		/*
 		 * if we reach here, not suitable replacement is available
-		 * <or> fragment interleave is NOT on. So stuff the sb_cc
+		 * <or> fragment interleave is NOT on. So stuff the sb_ccc
 		 * into the our held count, and its time to sleep again.
 		 */
-		held_length = so->so_rcv.sb_cc;
-		control->held_length = so->so_rcv.sb_cc;
+		held_length = so->so_rcv.sb_ccc;
+		control->held_length = so->so_rcv.sb_ccc;
 		goto restart;
 	}
 	/* Clear the held length since there is something to read */
@@ -5812,10 +5812,10 @@ get_more_data:
 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
 						sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, cp_len);
 					}
-					atomic_subtract_int(&so->so_rcv.sb_cc, cp_len);
+					atomic_subtract_int(&so->so_rcv.sb_ccc, cp_len);
 					if ((control->do_not_ref_stcb == 0) &&
 					    stcb) {
-						atomic_subtract_int(&stcb->asoc.sb_cc, cp_len);
+						atomic_subtract_int(&stcb->asoc.sb_ccc, cp_len);
 					}
 					copied_so_far += cp_len;
 					freed_so_far += cp_len;
@@ -5960,7 +5960,7 @@ wait_some_more:
 		    (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE))) {
 			goto release;
 		}
-		if (so->so_rcv.sb_cc <= control->held_length) {
+		if (so->so_rcv.sb_ccc <= control->held_length) {
 			error = sbwait(&so->so_rcv);
 			if (error) {
 				goto release;
@@ -5987,8 +5987,8 @@ wait_some_more:
 				}
 				goto done_with_control;
 			}
-			if (so->so_rcv.sb_cc > held_length) {
-				control->held_length = so->so_rcv.sb_cc;
+			if (so->so_rcv.sb_ccc > held_length) {
+				control->held_length = so->so_rcv.sb_ccc;
 				held_length = 0;
 			}
 			goto wait_some_more;
@@ -6135,13 +6135,13 @@ out:
 			    freed_so_far,
 			    ((uio) ? (slen - uio->uio_resid) : slen),
 			    stcb->asoc.my_rwnd,
-			    so->so_rcv.sb_cc);
+			    so->so_rcv.sb_ccc);
 		} else {
 			sctp_misc_ints(SCTP_SORECV_DONE,
 			    freed_so_far,
 			    ((uio) ? (slen - uio->uio_resid) : slen),
 			    0,
-			    so->so_rcv.sb_cc);
+			    so->so_rcv.sb_ccc);
 		}
 	}
 stage_left:
diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h
index 559daa3764fa..a9e72625c5e3 100644
--- a/sys/netinet/sctputil.h
+++ b/sys/netinet/sctputil.h
@@ -286,10 +286,10 @@ do { \
 		} \
 		if (stcb->sctp_socket && ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || \
 		    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { \
-			if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) { \
-				atomic_subtract_int(&((stcb)->sctp_socket->so_snd.sb_cc), tp1->book_size); \
+			if (stcb->sctp_socket->so_snd.sb_ccc >= tp1->book_size) { \
+				atomic_subtract_int(&((stcb)->sctp_socket->so_snd.sb_ccc), tp1->book_size); \
 			} else { \
-				stcb->sctp_socket->so_snd.sb_cc = 0; \
+				stcb->sctp_socket->so_snd.sb_ccc = 0; \
 			} \
 		} \
 	} \
@@ -307,10 +307,10 @@ do { \
 		} \
 		if (stcb->sctp_socket && ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || \
 		    (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { \
-			if (stcb->sctp_socket->so_snd.sb_cc >= sp->length) { \
-				atomic_subtract_int(&stcb->sctp_socket->so_snd.sb_cc,sp->length); \
+			if (stcb->sctp_socket->so_snd.sb_ccc >= sp->length) { \
+				atomic_subtract_int(&stcb->sctp_socket->so_snd.sb_ccc,sp->length); \
 			} else { \
-				stcb->sctp_socket->so_snd.sb_cc = 0; \
+				stcb->sctp_socket->so_snd.sb_ccc = 0; \
 			} \
 		} \
 	} \
@@ -322,7 +322,7 @@ do { \
 	if ((stcb->sctp_socket != NULL) && \
 	    ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || \
 	     (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { \
-		atomic_add_int(&stcb->sctp_socket->so_snd.sb_cc,sz); \
+		atomic_add_int(&stcb->sctp_socket->so_snd.sb_ccc,sz); \
 	} \
 } while (0)
 
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 468f14210565..e19d05ee318c 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -884,12 +884,10 @@ findpcb:
 		goto dropwithreset;
 	}
 	INP_WLOCK_ASSERT(inp);
-	if (!(inp->inp_flags & INP_HW_FLOWID)
-	    && (m->m_flags & M_FLOWID)
-	    && ((inp->inp_socket == NULL)
-		|| !(inp->inp_socket->so_options & SO_ACCEPTCONN))) {
-		inp->inp_flags |= INP_HW_FLOWID;
-		inp->inp_flags &= ~INP_SW_FLOWID;
+	if ((inp->inp_flowtype == M_HASHTYPE_NONE) &&
+	    (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) &&
+	    ((inp->inp_socket == NULL) ||
+	    (inp->inp_socket->so_options & SO_ACCEPTCONN) == 0)) {
 		inp->inp_flowid = m->m_pkthdr.flowid;
 		inp->inp_flowtype = M_HASHTYPE_GET(m);
 	}
@@ -1855,7 +1853,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
 					    newsize, so, NULL))
 						so->so_rcv.sb_flags &= ~SB_AUTOSIZE;
 				m_adj(m, drop_hdrlen);	/* delayed header drop */
-				sbappendstream_locked(&so->so_rcv, m);
+				sbappendstream_locked(&so->so_rcv, m, 0);
 			}
 			/* NB: sorwakeup_locked() does an implicit unlock. */
 			sorwakeup_locked(so);
@@ -2882,7 +2880,7 @@ dodata:							/* XXX */
 			if (so->so_rcv.sb_state & SBS_CANTRCVMORE)
 				m_freem(m);
 			else
-				sbappendstream_locked(&so->so_rcv, m);
+				sbappendstream_locked(&so->so_rcv, m, 0);
 			/* NB: sorwakeup_locked() does an implicit unlock. */
 			sorwakeup_locked(so);
 		} else {
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index dffee00f9b18..17d9a79eb50d 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -262,7 +262,7 @@ present:
 			m_freem(mq);
 		else {
 			mq->m_nextpkt = NULL;
-			sbappendstream_locked(&so->so_rcv, mq);
+			sbappendstream_locked(&so->so_rcv, mq, 0);
 			wakeup = 1;
 		}
 	}
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index 05c50769531b..c7570e2a26d7 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -713,9 +713,7 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
 	 * If there's an mbuf and it has a flowid, then let's initialise the
 	 * inp with that particular flowid.
 	 */
-	if (m != NULL && m->m_flags & M_FLOWID) {
-		inp->inp_flags |= INP_HW_FLOWID;
-		inp->inp_flags &= ~INP_SW_FLOWID;
+	if (m != NULL && M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) {
 		inp->inp_flowid = m->m_pkthdr.flowid;
 		inp->inp_flowtype = M_HASHTYPE_GET(m);
 	}
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 2820ffba70ed..dee1c33186ab 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -821,7 +821,11 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
 	if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
 		if (control)
 			m_freem(control);
-		if (m)
+		/*
+		 * In case of PRUS_NOTREADY, tcp_usr_ready() is responsible
+		 * for freeing memory.
+		 */
+		if (m && (flags & PRUS_NOTREADY) == 0)
 			m_freem(m);
 		error = ECONNRESET;
 		goto out;
@@ -843,7 +847,7 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
 		m_freem(control);	/* empty control, just free it */
 	}
 	if (!(flags & PRUS_OOB)) {
-		sbappendstream(&so->so_snd, m);
+		sbappendstream(&so->so_snd, m, flags);
 		if (nam && tp->t_state < TCPS_SYN_SENT) {
 			/*
 			 * Do implied connect if not yet connected,
@@ -875,7 +879,8 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
 			socantsendmore(so);
 			tcp_usrclosed(tp);
 		}
-		if (!(inp->inp_flags & INP_DROPPED)) {
+		if (!(inp->inp_flags & INP_DROPPED) &&
+		    !(flags & PRUS_NOTREADY)) {
 			if (flags & PRUS_MORETOCOME)
 				tp->t_flags |= TF_MORETOCOME;
 			error = tcp_output(tp);
@@ -901,7 +906,7 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
 		 * of data past the urgent section.
 		 * Otherwise, snd_up should be one lower.
 		 */
-		sbappendstream_locked(&so->so_snd, m);
+		sbappendstream_locked(&so->so_snd, m, flags);
 		SOCKBUF_UNLOCK(&so->so_snd);
 		if (nam && tp->t_state < TCPS_SYN_SENT) {
 			/*
@@ -925,10 +930,12 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
 			tp->snd_wnd = TTCP_CLIENT_SND_WND;
 			tcp_mss(tp, -1);
 		}
-		tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
-		tp->t_flags |= TF_FORCEDATA;
-		error = tcp_output(tp);
-		tp->t_flags &= ~TF_FORCEDATA;
+		tp->snd_up = tp->snd_una + sbavail(&so->so_snd);
+		if (!(flags & PRUS_NOTREADY)) {
+			tp->t_flags |= TF_FORCEDATA;
+			error = tcp_output(tp);
+			tp->t_flags &= ~TF_FORCEDATA;
+		}
 	}
 out:
 	TCPDEBUG2((flags & PRUS_OOB) ? PRU_SENDOOB :
@@ -939,6 +946,33 @@ out:
 	return (error);
 }
 
+static int
+tcp_usr_ready(struct socket *so, struct mbuf *m, int count)
+{
+	struct inpcb *inp;
+	struct tcpcb *tp;
+	int error;
+
+	inp = sotoinpcb(so);
+	INP_WLOCK(inp);
+	if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
+		INP_WUNLOCK(inp);
+		for (int i = 0; i < count; i++)
+			m = m_free(m);
+		return (ECONNRESET);
+	}
+	tp = intotcpcb(inp);
+
+	SOCKBUF_LOCK(&so->so_snd);
+	error = sbready(&so->so_snd, m, count);
+	SOCKBUF_UNLOCK(&so->so_snd);
+	if (error == 0)
+		error = tcp_output(tp);
+	INP_WUNLOCK(inp);
+
+	return (error);
+}
+
 /*
  * Abort the TCP.  Drop the connection abruptly.
  */
@@ -1073,6 +1107,7 @@ struct pr_usrreqs tcp_usrreqs = {
 	.pru_rcvd =		tcp_usr_rcvd,
 	.pru_rcvoob =		tcp_usr_rcvoob,
 	.pru_send =		tcp_usr_send,
+	.pru_ready =		tcp_usr_ready,
 	.pru_shutdown =		tcp_usr_shutdown,
 	.pru_sockaddr =		in_getsockaddr,
 	.pru_sosetlabel =	in_pcbsosetlabel,
@@ -1095,6 +1130,7 @@ struct pr_usrreqs tcp6_usrreqs = {
 	.pru_rcvd =		tcp_usr_rcvd,
 	.pru_rcvoob =		tcp_usr_rcvoob,
 	.pru_send =		tcp_usr_send,
+	.pru_ready =		tcp_usr_ready,
 	.pru_shutdown =		tcp_usr_shutdown,
 	.pru_sockaddr =		in6_mapped_sockaddr,
 	.pru_sosetlabel =	in_pcbsosetlabel,
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index c4ef9f07f708..5fd93b3bcff9 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1106,8 +1106,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
 	uint8_t pr;
 	uint16_t cscov = 0;
 	uint32_t flowid = 0;
-	int flowid_type = 0;
-	int use_flowid = 0;
+	uint8_t flowtype = M_HASHTYPE_NONE;
 
 	/*
 	 * udp_output() may need to temporarily bind or connect the current
@@ -1184,8 +1183,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
 					error = EINVAL;
 					break;
 				}
-				flowid_type = *(uint32_t *) CMSG_DATA(cm);
-				use_flowid = 1;
+				flowtype = *(uint32_t *) CMSG_DATA(cm);
 				break;
 
 #ifdef	RSS
@@ -1451,10 +1449,9 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
 	 * Once the UDP code decides to set a flowid some other way,
 	 * this allows the flowid to be overridden by userland.
 	 */
-	if (use_flowid) {
-		m->m_flags |= M_FLOWID;
+	if (flowtype != M_HASHTYPE_NONE) {
 		m->m_pkthdr.flowid = flowid;
-		M_HASHTYPE_SET(m, flowid_type);
+		M_HASHTYPE_SET(m, flowtype);
 #ifdef	RSS
 	} else {
 		uint32_t hash_val, hash_type;
@@ -1477,7 +1474,6 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
 		if (rss_proto_software_hash_v4(faddr, laddr, fport, lport,
 		    pr, &hash_val, &hash_type) == 0) {
 			m->m_pkthdr.flowid = hash_val;
-			m->m_flags |= M_FLOWID;
 			M_HASHTYPE_SET(m, hash_type);
 		}
 #endif
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 2a7b9dcf40f5..3b61849d4187 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -1252,7 +1252,7 @@ in6_pcblookup_mbuf(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
 	 * XXXRW: As above, that policy belongs in the pcbgroup code.
 	 */
 	if (in_pcbgroup_enabled(pcbinfo) &&
-	    !(M_HASHTYPE_TEST(m, M_HASHTYPE_NONE))) {
+	    M_HASHTYPE_TEST(m, M_HASHTYPE_NONE) == 0) {
 		pcbgroup = in6_pcbgroup_byhash(pcbinfo, M_HASHTYPE_GET(m),
 		    m->m_pkthdr.flowid);
 		if (pcbgroup != NULL)
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 4245a9fdb9e0..74d7483aa947 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -267,10 +267,10 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
 
 	if (inp != NULL) {
 		M_SETFIB(m, inp->inp_inc.inc_fibnum);
-		if (((flags & IP_NODEFAULTFLOWID) == 0) &&
-		(inp->inp_flags & (INP_HW_FLOWID|INP_SW_FLOWID))) {
+		if ((flags & IP_NODEFAULTFLOWID) == 0) {
+			/* unconditionally set flowid */
 			m->m_pkthdr.flowid = inp->inp_flowid;
-			m->m_flags |= M_FLOWID;
+			M_HASHTYPE_SET(m, inp->inp_flowtype);
 		}
 	}
 
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index 6c6f27a6e5d3..2b07b8e63fd9 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -843,7 +843,6 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
 		 */
 #ifdef	RSS
 		m->m_pkthdr.flowid = rss_hash_ip6_2tuple(*faddr, *laddr);
-		m->m_flags |= M_FLOWID;
 		M_HASHTYPE_SET(m, M_HASHTYPE_RSS_IPV6);
 #endif
 		flags = 0;
diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c
index a6eba64e1622..2e91d8529434 100644
--- a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c
+++ b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c
@@ -889,7 +889,7 @@ sdp_append(struct sdp_sock *ssk, struct sockbuf *sb, struct mbuf *mb, int cnt)
 		m_adj(mb, SDP_HEAD_SIZE);
 		n->m_pkthdr.len += mb->m_pkthdr.len;
 		n->m_flags |= mb->m_flags & (M_PUSH | M_URG);
-		m_demote(mb, 1);
+		m_demote(mb, 1, 0);
 		sbcompress(sb, mb, sb->sb_mbtail);
 		return;
 	}
diff --git a/sys/ofed/drivers/net/mlx4/en_rx.c b/sys/ofed/drivers/net/mlx4/en_rx.c
index 320462ec02ad..fa263266d67d 100644
--- a/sys/ofed/drivers/net/mlx4/en_rx.c
+++ b/sys/ofed/drivers/net/mlx4/en_rx.c
@@ -604,7 +604,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
 		}
 
 		mb->m_pkthdr.flowid = cq->ring;
-		mb->m_flags |= M_FLOWID;
+		M_HASHTYPE_SET(mb, M_HASHTYPE_OPAQUE);
 		mb->m_pkthdr.rcvif = dev;
 		if (be32_to_cpu(cqe->vlan_my_qpn) &
 		    MLX4_CQE_VLAN_PRESENT_MASK) {
diff --git a/sys/ofed/drivers/net/mlx4/en_tx.c b/sys/ofed/drivers/net/mlx4/en_tx.c
index d1931558bcc9..d92677fa5ce3 100644
--- a/sys/ofed/drivers/net/mlx4/en_tx.c
+++ b/sys/ofed/drivers/net/mlx4/en_tx.c
@@ -720,8 +720,11 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct mbuf *mb)
 	        up = (vlan_tag >> 13);
 	}
 
-	/* hash mbuf */
-	queue_index = mlx4_en_hashmbuf(MLX4_F_HASHL3 | MLX4_F_HASHL4, mb, hashrandom);
+	/* check if flowid is set */
+	if (M_HASHTYPE_GET(mb) != M_HASHTYPE_NONE)
+		queue_index = mb->m_pkthdr.flowid;
+	else
+		queue_index = mlx4_en_hashmbuf(MLX4_F_HASHL3 | MLX4_F_HASHL4, mb, hashrandom);
 
 	return ((queue_index % rings_p_up) + (up * rings_p_up));
 }
@@ -1066,15 +1069,11 @@ mlx4_en_transmit(struct ifnet *dev, struct mbuf *m)
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 	struct mlx4_en_tx_ring *ring;
 	struct mlx4_en_cq *cq;
-	int i = 0, err = 0;
+	int i, err = 0;
+
+	/* Compute which queue to use */
+	i = mlx4_en_select_queue(dev, m);
 
-	/* Which queue to use */
-	if ((m->m_flags & (M_FLOWID | M_VLANTAG)) == M_FLOWID) {
-		i = m->m_pkthdr.flowid % (priv->tx_ring_num - 1);
-	}
-	else {
-		i = mlx4_en_select_queue(dev, m);
-	}
 	ring = priv->tx_ring[i];
 
 	if (spin_trylock(&ring->tx_lock)) {
diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c
index 5864a02c4694..d1413a2c4aba 100644
--- a/sys/powerpc/aim/machdep.c
+++ b/sys/powerpc/aim/machdep.c
@@ -757,6 +757,10 @@ db_trap_glue(struct trapframe *frame)
 		|| frame->exc == EXC_BPT
 		|| frame->exc == EXC_DSI)) {
 		int type = frame->exc;
+
+		/* Ignore DTrace traps. */
+		if (*(uint32_t *)frame->srr0 == EXC_DTRACE) 
+			return (0);
 		if (type == EXC_PGM && (frame->srr1 & 0x20000)) {
 			type = T_BREAKPOINT;
 		}
diff --git a/sys/powerpc/aim/trap.c b/sys/powerpc/aim/trap.c
index cc54e593c00f..8276e96f1936 100644
--- a/sys/powerpc/aim/trap.c
+++ b/sys/powerpc/aim/trap.c
@@ -258,7 +258,8 @@ trap(struct trapframe *frame)
 			if (frame->srr1 & EXC_PGM_TRAP) {
 #ifdef KDTRACE_HOOKS
 				inst = fuword32((const void *)frame->srr0);
-				if (inst == 0x0FFFDDDD && dtrace_pid_probe_ptr != NULL) {
+				if (inst == 0x0FFFDDDD &&
+				    dtrace_pid_probe_ptr != NULL) {
 					struct reg regs;
 					fill_regs(td, &regs);
 					(*dtrace_pid_probe_ptr)(&regs);
@@ -301,7 +302,7 @@ trap(struct trapframe *frame)
 #ifdef KDTRACE_HOOKS
 		case EXC_PGM:
 			if (frame->srr1 & EXC_PGM_TRAP) {
-				if (*(uint32_t *)frame->srr0 == 0x7c810808) {
+				if (*(uint32_t *)frame->srr0 == EXC_DTRACE) {
 					if (dtrace_invop_jump_addr != NULL) {
 						dtrace_invop_jump_addr(frame);
 						return;
diff --git a/sys/powerpc/aim/trap_subr32.S b/sys/powerpc/aim/trap_subr32.S
index 56ca7155ddd0..2aae2a00abbc 100644
--- a/sys/powerpc/aim/trap_subr32.S
+++ b/sys/powerpc/aim/trap_subr32.S
@@ -890,8 +890,7 @@ CNAME(dblow):
 	mfcr	%r29			/* save CR in r29 */
 	mfsrr1	%r1
 	mtcr	%r1
-	bf	17,2f			/* branch if privileged */
-1:
+	bf	17,1f			/* branch if privileged */
 	/* Unprivileged case */
 	mtcr	%r29			/* put the condition register back */
         mfsprg2	%r29			/* ... and r29 */
@@ -900,19 +899,7 @@ CNAME(dblow):
 	li	%r1, 0	 		/* How to get the vector from LR */
 
         bla     generictrap		/* and we look like a generic trap */
-2:
-#ifdef KDTRACE_HOOKS
-	/* Privileged, so drop to KDB */
-	mfsrr0	%r1
-	mtsprg3	%r3
-	lwz	%r1,0(%r1)
-	/* Check if it's a DTrace trap. */
-	li	%r3,0x0808
-	addis	%r3,%r3,0x7c81
-	cmplw	%cr0,%r3,%r1
-	mfsprg3	%r3
-	beq	%cr0,1b
-#endif
+1:
 	/* Privileged, so drop to KDB */
 	GET_CPUINFO(%r1)
 	stw	%r28,(PC_DBSAVE+CPUSAVE_R28)(%r1)	/* free r28 */
diff --git a/sys/powerpc/aim/trap_subr64.S b/sys/powerpc/aim/trap_subr64.S
index bedf1f1962c4..0dc46b34e866 100644
--- a/sys/powerpc/aim/trap_subr64.S
+++ b/sys/powerpc/aim/trap_subr64.S
@@ -799,9 +799,8 @@ CNAME(dblow):
 	mfcr	%r29			/* save CR in r29 */
 	mfsrr1	%r1
 	mtcr	%r1
-	bf	17,2f			/* branch if privileged */
+	bf	17,1f			/* branch if privileged */
 
-1:
 	/* Unprivileged case */
 	mtcr	%r29			/* put the condition register back */
         mfsprg2	%r29			/* ... and r29 */
@@ -810,19 +809,7 @@ CNAME(dblow):
 	li	%r1, 0	 		/* How to get the vector from LR */
 
         bla     generictrap		/* and we look like a generic trap */
-2:
-#ifdef KDTRACE_HOOKS
-	/* Privileged, so drop to KDB */
-	mfsrr0	%r1
-	mtsprg3	%r3
-	lwz	%r1,0(%r1)
-	/* Check if it's a DTrace trap. */
-	li	%r3,0x0808
-	addis	%r3,%r3,0x7c81
-	cmplw	%cr0,%r3,%r1
-	mfsprg3	%r3
-	beq	%cr0,1b
-#endif
+1:
 	GET_CPUINFO(%r1)
 	std	%r27,(PC_DBSAVE+CPUSAVE_R27)(%r1)	/* free r27 */
 	std	%r28,(PC_DBSAVE+CPUSAVE_R28)(%r1)	/* free r28 */
diff --git a/sys/powerpc/include/trap.h b/sys/powerpc/include/trap.h
index 89f596659cfb..211afcf78225 100644
--- a/sys/powerpc/include/trap.h
+++ b/sys/powerpc/include/trap.h
@@ -120,6 +120,9 @@
 #define	EXC_PGM_PRIV		(1UL << 18)
 #define	EXC_PGM_TRAP		(1UL << 17)
 
+/* DTrace trap opcode. */
+#define EXC_DTRACE	0x7c810808
+
 #ifndef LOCORE
 struct	trapframe;
 struct	pcb;
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index 190900c43d22..ac3cfb2d0ced 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -950,7 +950,7 @@ struct mbuf	*m_copypacket(struct mbuf *, int);
 void		 m_copy_pkthdr(struct mbuf *, struct mbuf *);
 struct mbuf	*m_copyup(struct mbuf *, int, int);
 struct mbuf	*m_defrag(struct mbuf *, int);
-void		 m_demote(struct mbuf *, int);
+void		 m_demote(struct mbuf *, int, int);
 struct mbuf	*m_devget(char *, int, int, struct ifnet *,
 		    void (*)(char *, caddr_t, u_int));
 struct mbuf	*m_dup(struct mbuf *, int);
diff --git a/sys/sys/protosw.h b/sys/sys/protosw.h
index 2d98a4c25edd..55db0e339699 100644
--- a/sys/sys/protosw.h
+++ b/sys/sys/protosw.h
@@ -208,6 +208,8 @@ struct pr_usrreqs {
 #define	PRUS_OOB	0x1
 #define	PRUS_EOF	0x2
 #define	PRUS_MORETOCOME	0x4
+#define	PRUS_NOTREADY	0x8
+	int	(*pru_ready)(struct socket *so, struct mbuf *m, int count);
 	int	(*pru_sense)(struct socket *so, struct stat *sb);
 	int	(*pru_shutdown)(struct socket *so);
 	int	(*pru_flush)(struct socket *so, int direction);
@@ -251,6 +253,7 @@ int	pru_rcvd_notsupp(struct socket *so, int flags);
 int	pru_rcvoob_notsupp(struct socket *so, struct mbuf *m, int flags);
 int	pru_send_notsupp(struct socket *so, int flags, struct mbuf *m,
 	    struct sockaddr *addr, struct mbuf *control, struct thread *td);
+int	pru_ready_notsupp(struct socket *so, struct mbuf *m, int count);
 int	pru_sense_null(struct socket *so, struct stat *sb);
 int	pru_shutdown_notsupp(struct socket *so);
 int	pru_sockaddr_notsupp(struct socket *so, struct sockaddr **nam);
diff --git a/sys/sys/sockbuf.h b/sys/sys/sockbuf.h
index f9e8da4cde0b..5bd9bb556251 100644
--- a/sys/sys/sockbuf.h
+++ b/sys/sys/sockbuf.h
@@ -89,8 +89,10 @@ struct	sockbuf {
 	struct	mbuf *sb_lastrecord;	/* (c/d) first mbuf of last
 					 * record in socket buffer */
 	struct	mbuf *sb_sndptr; /* (c/d) pointer into mbuf chain */
+	struct	mbuf *sb_fnrdy;	/* (c/d) pointer to first not ready buffer */
 	u_int	sb_sndptroff;	/* (c/d) byte offset of ptr into chain */
-	u_int	sb_cc;		/* (c/d) actual chars in buffer */
+	u_int	sb_acc;		/* (c/d) available chars in buffer */
+	u_int	sb_ccc;		/* (c/d) claimed chars in buffer */
 	u_int	sb_hiwat;	/* (c/d) max actual char count */
 	u_int	sb_mbcnt;	/* (c/d) chars of mbufs used */
 	u_int   sb_mcnt;        /* (c/d) number of mbufs in buffer */
@@ -120,10 +122,17 @@ struct	sockbuf {
 #define	SOCKBUF_LOCK_ASSERT(_sb)	mtx_assert(SOCKBUF_MTX(_sb), MA_OWNED)
 #define	SOCKBUF_UNLOCK_ASSERT(_sb)	mtx_assert(SOCKBUF_MTX(_sb), MA_NOTOWNED)
 
+/*
+ * Socket buffer private mbuf(9) flags.
+ */
+#define	M_NOTREADY	M_PROTO1	/* m_data not populated yet */
+#define	M_BLOCKED	M_PROTO2	/* M_NOTREADY in front of m */
+#define	M_NOTAVAIL	(M_NOTREADY | M_BLOCKED)
+
 void	sbappend(struct sockbuf *sb, struct mbuf *m);
 void	sbappend_locked(struct sockbuf *sb, struct mbuf *m);
-void	sbappendstream(struct sockbuf *sb, struct mbuf *m);
-void	sbappendstream_locked(struct sockbuf *sb, struct mbuf *m);
+void	sbappendstream(struct sockbuf *sb, struct mbuf *m, int flags);
+void	sbappendstream_locked(struct sockbuf *sb, struct mbuf *m, int flags);
 int	sbappendaddr(struct sockbuf *sb, const struct sockaddr *asa,
 	    struct mbuf *m0, struct mbuf *control);
 int	sbappendaddr_locked(struct sockbuf *sb, const struct sockaddr *asa,
@@ -136,7 +145,6 @@ int	sbappendcontrol_locked(struct sockbuf *sb, struct mbuf *m0,
 	    struct mbuf *control);
 void	sbappendrecord(struct sockbuf *sb, struct mbuf *m0);
 void	sbappendrecord_locked(struct sockbuf *sb, struct mbuf *m0);
-void	sbcheck(struct sockbuf *sb);
 void	sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n);
 struct mbuf *
 	sbcreatecontrol(caddr_t p, int size, int type, int level);
@@ -164,10 +172,13 @@ void	sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb);
 int	sbwait(struct sockbuf *sb);
 int	sblock(struct sockbuf *sb, int flags);
 void	sbunlock(struct sockbuf *sb);
+void	sballoc(struct sockbuf *, struct mbuf *);
+void	sbfree(struct sockbuf *, struct mbuf *);
+int	sbready(struct sockbuf *, struct mbuf *, int);
 
 /*
  * Return how much data is available to be taken out of socket
- * bufffer right now.
+ * buffer right now.
  */
 static inline u_int
 sbavail(struct sockbuf *sb)
@@ -176,7 +187,7 @@ sbavail(struct sockbuf *sb)
 #if 0
 	SOCKBUF_LOCK_ASSERT(sb);
 #endif
-	return (sb->sb_cc);
+	return (sb->sb_acc);
 }
 
 /*
@@ -190,59 +201,30 @@ sbused(struct sockbuf *sb)
 #if 0
 	SOCKBUF_LOCK_ASSERT(sb);
 #endif
-	return (sb->sb_cc);
+	return (sb->sb_ccc);
 }
 
 /*
  * How much space is there in a socket buffer (so->so_snd or so->so_rcv)?
  * This is problematical if the fields are unsigned, as the space might
- * still be negative (cc > hiwat or mbcnt > mbmax).  Should detect
- * overflow and return 0.  Should use "lmin" but it doesn't exist now.
+ * still be negative (ccc > hiwat or mbcnt > mbmax).
  */
-static __inline
-long
+static inline long
 sbspace(struct sockbuf *sb)
 {
-	long bleft;
-	long mleft;
+	long bleft, mleft;
+
+#if 0
+	SOCKBUF_LOCK_ASSERT(sb);
+#endif
 
 	if (sb->sb_flags & SB_STOP)
 		return(0);
-	bleft = sb->sb_hiwat - sb->sb_cc;
+
+	bleft = sb->sb_hiwat - sb->sb_ccc;
 	mleft = sb->sb_mbmax - sb->sb_mbcnt;
-	return((bleft < mleft) ? bleft : mleft);
-}
 
-/* adjust counters in sb reflecting allocation of m */
-#define	sballoc(sb, m) { \
-	(sb)->sb_cc += (m)->m_len; \
-	if ((m)->m_type != MT_DATA && (m)->m_type != MT_OOBDATA) \
-		(sb)->sb_ctl += (m)->m_len; \
-	(sb)->sb_mbcnt += MSIZE; \
-	(sb)->sb_mcnt += 1; \
-	if ((m)->m_flags & M_EXT) { \
-		(sb)->sb_mbcnt += (m)->m_ext.ext_size; \
-		(sb)->sb_ccnt += 1; \
-	} \
-}
-
-/* adjust counters in sb reflecting freeing of m */
-#define	sbfree(sb, m) { \
-	(sb)->sb_cc -= (m)->m_len; \
-	if ((m)->m_type != MT_DATA && (m)->m_type != MT_OOBDATA) \
-		(sb)->sb_ctl -= (m)->m_len; \
-	(sb)->sb_mbcnt -= MSIZE; \
-	(sb)->sb_mcnt -= 1; \
-	if ((m)->m_flags & M_EXT) { \
-		(sb)->sb_mbcnt -= (m)->m_ext.ext_size; \
-		(sb)->sb_ccnt -= 1; \
-	} \
-	if ((sb)->sb_sndptr == (m)) { \
-		(sb)->sb_sndptr = NULL; \
-		(sb)->sb_sndptroff = 0; \
-	} \
-	if ((sb)->sb_sndptroff != 0) \
-		(sb)->sb_sndptroff -= (m)->m_len; \
+	return ((bleft < mleft) ? bleft : mleft);
 }
 
 #define SB_EMPTY_FIXUP(sb) do {						\
@@ -254,13 +236,15 @@ sbspace(struct sockbuf *sb)
 
 #ifdef SOCKBUF_DEBUG
 void	sblastrecordchk(struct sockbuf *, const char *, int);
-#define	SBLASTRECORDCHK(sb)	sblastrecordchk((sb), __FILE__, __LINE__)
-
 void	sblastmbufchk(struct sockbuf *, const char *, int);
+void	sbcheck(struct sockbuf *, const char *, int);
+#define	SBLASTRECORDCHK(sb)	sblastrecordchk((sb), __FILE__, __LINE__)
 #define	SBLASTMBUFCHK(sb)	sblastmbufchk((sb), __FILE__, __LINE__)
+#define	SBCHECK(sb)		sbcheck((sb), __FILE__, __LINE__)
 #else
-#define	SBLASTRECORDCHK(sb)      /* nothing */
-#define	SBLASTMBUFCHK(sb)        /* nothing */
+#define	SBLASTRECORDCHK(sb)	do {} while (0)
+#define	SBLASTMBUFCHK(sb)	do {} while (0)
+#define	SBCHECK(sb)		do {} while (0)
 #endif /* SOCKBUF_DEBUG */
 
 #endif /* _KERNEL */
diff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c
index 50e66c058268..574eba073f54 100644
--- a/sys/vm/uma_core.c
+++ b/sys/vm/uma_core.c
@@ -146,6 +146,8 @@ static LIST_HEAD(,uma_slab) uma_boot_pages =
 /* This mutex protects the boot time pages list */
 static struct mtx_padalign uma_boot_pages_mtx;
 
+static struct sx uma_drain_lock;
+
 /* Is the VM done starting up? */
 static int booted = 0;
 #define	UMA_STARTUP	1
@@ -1876,6 +1878,7 @@ uma_startup2(void)
 {
 	booted = UMA_STARTUP2;
 	bucket_enable();
+	sx_init(&uma_drain_lock, "umadrain");
 #ifdef UMA_DEBUG
 	printf("UMA startup2 complete.\n");
 #endif
@@ -1930,6 +1933,8 @@ uma_zcreate(const char *name, size_t size, uma_ctor ctor, uma_dtor dtor,
 
 {
 	struct uma_zctor_args args;
+	uma_zone_t res;
+	bool locked;
 
 	/* This stuff is essential for the zone ctor */
 	memset(&args, 0, sizeof(args));
@@ -1943,7 +1948,16 @@ uma_zcreate(const char *name, size_t size, uma_ctor ctor, uma_dtor dtor,
 	args.flags = flags;
 	args.keg = NULL;
 
-	return (zone_alloc_item(zones, &args, M_WAITOK));
+	if (booted < UMA_STARTUP2) {
+		locked = false;
+	} else {
+		sx_slock(&uma_drain_lock);
+		locked = true;
+	}
+	res = zone_alloc_item(zones, &args, M_WAITOK);
+	if (locked)
+		sx_sunlock(&uma_drain_lock);
+	return (res);
 }
 
 /* See uma.h */
@@ -1953,6 +1967,8 @@ uma_zsecond_create(char *name, uma_ctor ctor, uma_dtor dtor,
 {
 	struct uma_zctor_args args;
 	uma_keg_t keg;
+	uma_zone_t res;
+	bool locked;
 
 	keg = zone_first_keg(master);
 	memset(&args, 0, sizeof(args));
@@ -1966,8 +1982,17 @@ uma_zsecond_create(char *name, uma_ctor ctor, uma_dtor dtor,
 	args.flags = keg->uk_flags | UMA_ZONE_SECONDARY;
 	args.keg = keg;
 
+	if (booted < UMA_STARTUP2) {
+		locked = false;
+	} else {
+		sx_slock(&uma_drain_lock);
+		locked = true;
+	}
 	/* XXX Attaches only one keg of potentially many. */
-	return (zone_alloc_item(zones, &args, M_WAITOK));
+	res = zone_alloc_item(zones, &args, M_WAITOK);
+	if (locked)
+		sx_sunlock(&uma_drain_lock);
+	return (res);
 }
 
 /* See uma.h */
@@ -2085,7 +2110,9 @@ void
 uma_zdestroy(uma_zone_t zone)
 {
 
+	sx_slock(&uma_drain_lock);
 	zone_free_item(zones, zone, NULL, SKIP_NONE);
+	sx_sunlock(&uma_drain_lock);
 }
 
 /* See uma.h */
@@ -3205,6 +3232,7 @@ uma_reclaim(void)
 #ifdef UMA_DEBUG
 	printf("UMA: vm asked us to release pages!\n");
 #endif
+	sx_xlock(&uma_drain_lock);
 	bucket_enable();
 	zone_foreach(zone_drain);
 	if (vm_page_count_min()) {
@@ -3219,6 +3247,7 @@ uma_reclaim(void)
 	zone_drain(slabzone);
 	zone_drain(slabrefzone);
 	bucket_zone_drain();
+	sx_xunlock(&uma_drain_lock);
 }
 
 /* See uma.h */
diff --git a/tools/tools/shlib-compat/shlib-compat.py b/tools/tools/shlib-compat/shlib-compat.py
index 726c53ffb967..ca6f036639d1 100755
--- a/tools/tools/shlib-compat/shlib-compat.py
+++ b/tools/tools/shlib-compat/shlib-compat.py
@@ -60,6 +60,14 @@ class Config(object):
     origfile = FileConfig()
     newfile = FileConfig()
 
+    exclude_sym_default = [
+            '^__bss_start$',
+            '^_edata$',
+            '^_end$',
+            '^_fini$',
+            '^_init$',
+            ]
+
     @classmethod
     def init(cls):
         cls.version_filter = StrFilter()
@@ -338,15 +346,17 @@ class BaseTypeDef(Def):
     def _pp(self, pp):
         if self.encoding in self.inttypes:
             sign = '' if self.encoding == 'DW_ATE_signed' else 'u'
-            bits = int(self.byte_size) * 8
+            bits = int(self.byte_size, 0) * 8
             return '%sint%s_t' % (sign, bits)
-        elif self.encoding == 'DW_ATE_signed_char' and int(self.byte_size) == 1:
+        elif self.encoding == 'DW_ATE_signed_char' and int(self.byte_size, 0) == 1:
             return 'char';
+        elif self.encoding == 'DW_ATE_boolean' and int(self.byte_size, 0) == 1:
+            return 'bool';
         elif self.encoding == 'DW_ATE_float':
-            return self._mapval(self.byte_size, {
-                '16': 'long double',
-                '8': 'double',
-                '4': 'float',
+            return self._mapval(int(self.byte_size, 0), {
+                16: 'long double',
+                8: 'double',
+                4: 'float',
             })
         raise NotImplementedError('Invalid encoding: %s' % self)
 
@@ -374,6 +384,11 @@ class VolatileTypeDef(AnonymousDef):
     def _pp(self, pp):
         return 'volatile ' + self.type._pp(pp)
 
+class RestrictTypeDef(AnonymousDef):
+    _is_alias = True
+    def _pp(self, pp):
+        return 'restrict ' + self.type._pp(pp)
+
 class ArrayDef(AnonymousDef):
     def _pp(self, pp):
         t = pp.run(self.type)
@@ -411,6 +426,11 @@ class ParameterDef(Def):
         t = pp.run(self.type)
         return "%s %s" % (t, self._name_opt())
 
+class VariableDef(Def):
+    def _pp(self, pp):
+        t = pp.run(self.type)
+        return "%s %s" % (t, self._name_opt())
+
 # TODO
 class StructForwardDef(Def):
     pass
@@ -485,6 +505,10 @@ class Dwarf(object):
         result = self._build_optarg_type(raw)
         return FunctionDef(raw.id, raw.name, params=params, result=result)
 
+    def build_variable(self, raw):
+        type = self._build_optarg_type(raw)
+        return VariableDef(raw.id, raw.optname, type=type)
+
     def build_subroutine_type(self, raw):
         params = [ self.build(x) for x in raw.nested ]
         result = self._build_optarg_type(raw)
@@ -547,6 +571,10 @@ class Dwarf(object):
         type = self._build_optarg_type(raw)
         return VolatileTypeDef(raw.id, type=type)
 
+    def build_restrict_type(self, raw):
+        type = self._build_optarg_type(raw)
+        return RestrictTypeDef(raw.id, type=type)
+
     def build_enumeration_type(self, raw):
         # TODO handle DW_TAG_enumerator ???
         return EnumerationTypeDef(raw.id, name=raw.optname,
@@ -574,7 +602,7 @@ class Dwarf(object):
             return int(id)
         except ValueError:
             if (id.startswith('<') and id.endswith('>')):
-                return int(id[1:-1])
+                return int(id[1:-1], 0)
             else:
                 raise ValueError("Invalid dwarf id: %s" % id)
 
@@ -782,7 +810,7 @@ class DwarfdumpParser(Parser):
     class Tag(object):
         def __init__(self, unit, data):
             self.unit = unit
-            self.id = int(data['id'])
+            self.id = int(data['id'], 0)
             self.level = int(data['level'])
             self.tag = data['tag']
             self.args = {}
@@ -816,7 +844,7 @@ class DwarfdumpParser(Parser):
         def __repr__(self):
             return "Tag(%d, %d, %s)" % (self.level, self.id, self.tag)
 
-    re_header = re.compile('<(?P<level>\d+)><(?P<id>\d+\+*\d*)><(?P<tag>\w+)>')
+    re_header = re.compile('<(?P<level>\d+)><(?P<id>[0xX0-9a-fA-F]+(?:\+(0[xX])?[0-9a-fA-F]+)?)><(?P<tag>\w+)>')
     re_argname = re.compile('(?P<arg>\w+)<')
     re_argunknown = re.compile('<Unknown AT value \w+><[^<>]+>')
 
@@ -827,6 +855,10 @@ class DwarfdumpParser(Parser):
         'DW_TAG_variable',
         ])
 
+    external_tags = set([
+        'DW_TAG_variable',
+        ])
+
     def __init__(self, libfile):
         Parser.__init__(self, "%s -di %s" % (Config.dwarfdump, libfile))
         self.current_unit = None
@@ -888,9 +920,19 @@ class DwarfdumpParser(Parser):
         while args:
             args = self.parse_arg(tag, args)
         tag.unit.tags[tag.id] = tag
-        if tag.args.has_key('DW_AT_low_pc') and \
-                tag.tag not in DwarfdumpParser.skip_tags:
-            offset = int(tag.args['DW_AT_low_pc'], 16)
+        def parse_offset(tag):
+            if tag.args.has_key('DW_AT_low_pc'):
+                return int(tag.args['DW_AT_low_pc'], 16)
+            elif tag.args.has_key('DW_AT_location'):
+                location = tag.args['DW_AT_location']
+                if location.startswith('DW_OP_addr'):
+                    return int(location.replace('DW_OP_addr', ''), 16)
+            return None
+        offset = parse_offset(tag)
+        if offset is not None and \
+                (tag.tag not in DwarfdumpParser.skip_tags or \
+                (tag.args.has_key('DW_AT_external') and \
+                tag.tag in DwarfdumpParser.external_tags)):
             if self.offsetmap.has_key(offset):
                 raise ValueError("Dwarf dump parse error: " +
                         "symbol is aleady defined at offset 0x%x" % offset)
@@ -963,10 +1005,15 @@ def cmp_symbols(commonver):
         names.sort()
         for symname in names:
             sym = ver.symbols[symname]
-            match = sym.origsym.definition == sym.newsym.definition
+            missing = sym.origsym.definition is None or sym.newsym.definition is None
+            match = not missing and sym.origsym.definition == sym.newsym.definition
             if not match:
                 App.result_code = 1
             if Config.verbose >= 1 or not match:
+                if missing:
+                    print '%s: missing definition' % \
+                            (sym.origsym.name_ver,)
+                    continue
                 print '%s: definitions %smatch' % \
                         (sym.origsym.name_ver, "" if match else "mis")
                 if Config.dump or (not match and not Config.no_dump):
@@ -1035,10 +1082,16 @@ if __name__ == '__main__':
             help="result output file for original library", metavar="ORIGFILE")
     parser.add_option('--out-new', action='store',
             help="result output file for new library", metavar="NEWFILE")
+    parser.add_option('--dwarfdump', action='store',
+            help="path to dwarfdump executable", metavar="DWARFDUMP")
+    parser.add_option('--objdump', action='store',
+            help="path to objdump executable", metavar="OBJDUMP")
     parser.add_option('--exclude-ver', action='append', metavar="RE")
     parser.add_option('--include-ver', action='append', metavar="RE")
     parser.add_option('--exclude-sym', action='append', metavar="RE")
     parser.add_option('--include-sym', action='append', metavar="RE")
+    parser.add_option('--no-exclude-sym-default', action='store_true',
+            help="don't exclude special symbols like _init, _end, __bss_start")
     for opt in ['alias', 'cached', 'symbol']:
         parser.add_option("--w-" + opt,
                 action="store_true", dest="w_" + opt)
@@ -1049,6 +1102,10 @@ if __name__ == '__main__':
     if len(args) != 2:
         parser.print_help()
         sys.exit(-1)
+    if opts.dwarfdump:
+        Config.dwarfdump = opts.dwarfdump
+    if opts.objdump:
+        Config.objdump = opts.objdump
     if opts.out_orig:
         Config.origfile.init(opts.out_orig)
     if opts.out_new:
@@ -1071,6 +1128,8 @@ if __name__ == '__main__':
             opt = getattr(opts, a + k)
             if opt:
                 getattr(v, a).extend(opt)
+    if not opts.no_exclude_sym_default:
+        Config.symbol_filter.exclude.extend(Config.exclude_sym_default)
     Config.version_filter.compile()
     Config.symbol_filter.compile()
     for w in ['w_alias', 'w_cached', 'w_symbol']:
diff --git a/tools/tools/shlib-compat/test/Makefile.inc b/tools/tools/shlib-compat/test/Makefile.inc
index 14aaef6ea956..e1a0719a89f4 100644
--- a/tools/tools/shlib-compat/test/Makefile.inc
+++ b/tools/tools/shlib-compat/test/Makefile.inc
@@ -11,3 +11,5 @@ DEBUG_FLAGS?=	-g
 
 VERSION_DEF=	${.CURDIR}/../Versions.def
 SYMBOL_MAPS=	${.CURDIR}/Symbol.map
+
+MK_DEBUG_FILES=	yes
diff --git a/tools/tools/shlib-compat/test/regress.sh b/tools/tools/shlib-compat/test/regress.sh
index e113cce87b63..0789fa8b3cf7 100755
--- a/tools/tools/shlib-compat/test/regress.sh
+++ b/tools/tools/shlib-compat/test/regress.sh
@@ -1,7 +1,7 @@
 #!/bin/sh
 # $FreeBSD$
 
-run() { ../shlib-compat.py --no-dump -vv libtest$1/libtest$1.so.0.debug libtest$2/libtest$2.so.0.debug; }
+run() { ../shlib-compat.py --no-dump -vv libtest$1/libtest$1.so.0.full libtest$2/libtest$2.so.0.full; }
 echo 1..9
 REGRESSION_START($1)
 REGRESSION_TEST(`1-1', `run 1 1')
diff --git a/tools/tools/sysbuild/sysbuild.sh b/tools/tools/sysbuild/sysbuild.sh
index 1a32c60e027e..bb22a697453a 100644
--- a/tools/tools/sysbuild/sysbuild.sh
+++ b/tools/tools/sysbuild/sysbuild.sh
@@ -226,8 +226,7 @@ ports_build() (
 		t=`echo $p | sed 's,/usr/ports/,,'`
 		pn=`cd $p && make package-name`
 
-		if [ "x$p" == "x/usr/ports/ports-mgmt/pkg" -o \
-		     "x$p" == "x/freebsd/ports/ports-mgmt/pkg" ] ; then
+		if [ "x`basename $p`" == "xpkg" ] ; then
 			log_it "Very Special: $t ($pn)"
 
 			(
diff --git a/usr.bin/bluetooth/btsockstat/btsockstat.c b/usr.bin/bluetooth/btsockstat/btsockstat.c
index f63ee1fe5f7a..20f4de8076c8 100644
--- a/usr.bin/bluetooth/btsockstat/btsockstat.c
+++ b/usr.bin/bluetooth/btsockstat/btsockstat.c
@@ -255,8 +255,8 @@ hcirawpr(kvm_t *kvmd, u_long addr)
 			(unsigned long) pcb.so,
 			(unsigned long) this,
 			pcb.flags,
-			so.so_rcv.sb_cc,
-			so.so_snd.sb_cc,
+			so.so_rcv.sb_ccc,
+			so.so_snd.sb_ccc,
 			pcb.addr.hci_node);
 	}
 } /* hcirawpr */
@@ -303,8 +303,8 @@ l2caprawpr(kvm_t *kvmd, u_long addr)
 "%-8lx %-8lx %6d %6d %-17.17s\n",
 			(unsigned long) pcb.so,
 			(unsigned long) this,
-			so.so_rcv.sb_cc,
-			so.so_snd.sb_cc,
+			so.so_rcv.sb_ccc,
+			so.so_snd.sb_ccc,
 			bdaddrpr(&pcb.src, NULL, 0));
 	}
 } /* l2caprawpr */
@@ -361,8 +361,8 @@ l2cappr(kvm_t *kvmd, u_long addr)
 		fprintf(stdout,
 "%-8lx %6d %6d %-17.17s/%-5d %-17.17s %-5d %s\n",
 			(unsigned long) this,
-			so.so_rcv.sb_cc,
-			so.so_snd.sb_cc,
+			so.so_rcv.sb_ccc,
+			so.so_snd.sb_ccc,
 			bdaddrpr(&pcb.src, local, sizeof(local)),
 			pcb.psm,
 			bdaddrpr(&pcb.dst, remote, sizeof(remote)),
@@ -467,8 +467,8 @@ rfcommpr(kvm_t *kvmd, u_long addr)
 		fprintf(stdout,
 "%-8lx %6d %6d %-17.17s %-17.17s %-4d %-4d %s\n",
 			(unsigned long) this,
-			so.so_rcv.sb_cc,
-			so.so_snd.sb_cc,
+			so.so_rcv.sb_ccc,
+			so.so_snd.sb_ccc,
 			bdaddrpr(&pcb.src, local, sizeof(local)),
 			bdaddrpr(&pcb.dst, remote, sizeof(remote)),
 			pcb.channel,
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
index 10d0698e6beb..c22e49f62405 100644
--- a/usr.bin/netstat/inet.c
+++ b/usr.bin/netstat/inet.c
@@ -137,7 +137,7 @@ pcblist_sysctl(int proto, const char *name, char **bufp, int istcp __unused)
 static void
 sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb)
 {
-	xsb->sb_cc = sb->sb_cc;
+	xsb->sb_cc = sb->sb_ccc;
 	xsb->sb_hiwat = sb->sb_hiwat;
 	xsb->sb_mbcnt = sb->sb_mbcnt;
 	xsb->sb_mcnt = sb->sb_mcnt;
@@ -479,7 +479,8 @@ protopr(u_long off, const char *name, int af1, int proto)
 				printf("%6u %6u %6u ", tp->t_sndrexmitpack,
 				       tp->t_rcvoopack, tp->t_sndzerowin);
 		} else {
-			printf("%6u %6u ", so->so_rcv.sb_cc, so->so_snd.sb_cc);
+			printf("%6u %6u ",
+			    so->so_rcv.sb_cc, so->so_snd.sb_cc);
 		}
 		if (numeric_port) {
 			if (inp->inp_vflag & INP_IPV4) {
diff --git a/usr.bin/netstat/netgraph.c b/usr.bin/netstat/netgraph.c
index 95578af739fa..9a08b6d282c8 100644
--- a/usr.bin/netstat/netgraph.c
+++ b/usr.bin/netstat/netgraph.c
@@ -119,7 +119,7 @@ netgraphprotopr(u_long off, const char *name, int af1 __unused,
 		if (Aflag)
 			printf("%8lx ", (u_long) this);
 		printf("%-5.5s %6u %6u ",
-		    name, sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc);
+		    name, sockb.so_rcv.sb_ccc, sockb.so_snd.sb_ccc);
 
 		/* Get info on associated node */
 		if (ngpcb.node_id == 0 || csock == -1)
diff --git a/usr.bin/netstat/unix.c b/usr.bin/netstat/unix.c
index 027e812cf7cd..a5cc037840be 100644
--- a/usr.bin/netstat/unix.c
+++ b/usr.bin/netstat/unix.c
@@ -287,7 +287,8 @@ unixdomainpr(struct xunpcb *xunp, struct xsocket *so)
 	} else {
 		printf("%8lx %-6.6s %6u %6u %8lx %8lx %8lx %8lx",
 		    (long)so->so_pcb, socktype[so->so_type], so->so_rcv.sb_cc,
-		    so->so_snd.sb_cc, (long)unp->unp_vnode, (long)unp->unp_conn,
+		    so->so_snd.sb_cc, (long)unp->unp_vnode,
+		    (long)unp->unp_conn,
 		    (long)LIST_FIRST(&unp->unp_refs),
 		    (long)LIST_NEXT(unp, unp_reflink));
 	}
diff --git a/usr.bin/systat/netstat.c b/usr.bin/systat/netstat.c
index bb1318da37c8..b5938eb9d911 100644
--- a/usr.bin/systat/netstat.c
+++ b/usr.bin/systat/netstat.c
@@ -333,8 +333,8 @@ enter_kvm(struct inpcb *inp, struct socket *so, int state, const char *proto)
 	struct netinfo *p;
 
 	if ((p = enter(inp, state, proto)) != NULL) {
-		p->ni_rcvcc = so->so_rcv.sb_cc;
-		p->ni_sndcc = so->so_snd.sb_cc;
+		p->ni_rcvcc = so->so_rcv.sb_ccc;
+		p->ni_sndcc = so->so_snd.sb_ccc;
 	}
 }