Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Jun 2016 11:39:37 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r302277 - in projects/vnet: . lib/libc/rpc lib/libc/tests/ssp lib/libc/yp sbin/natd share/man/man4 share/man/man5 share/man/man9 sys/cddl/contrib/opensolaris/uts/common/fs/zfs sys/dev/c...
Message-ID:  <201606291139.u5TBdbN4080092@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Wed Jun 29 11:39:37 2016
New Revision: 302277
URL: https://svnweb.freebsd.org/changeset/base/302277

Log:
  MfH @r302276
  
  Sponsored by:	The FreeBSD Foundation

Added:
  projects/vnet/share/man/man9/tcp_functions.9
     - copied unchanged from r302276, head/share/man/man9/tcp_functions.9
  projects/vnet/tools/build/options/WITH_EXTRA_TCP_STACKS
     - copied unchanged from r302276, head/tools/build/options/WITH_EXTRA_TCP_STACKS
Modified:
  projects/vnet/Makefile.inc1
  projects/vnet/Makefile.libcompat
  projects/vnet/lib/libc/rpc/Makefile.inc
  projects/vnet/lib/libc/tests/ssp/Makefile
  projects/vnet/lib/libc/yp/Makefile.inc
  projects/vnet/sbin/natd/natd.c
  projects/vnet/share/man/man4/tcp.4
  projects/vnet/share/man/man5/src.conf.5
  projects/vnet/share/man/man9/Makefile
  projects/vnet/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
  projects/vnet/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_pool.c
  projects/vnet/sys/dev/cxgbe/t4_main.c
  projects/vnet/sys/dev/cxgbe/tom/t4_listen.c
  projects/vnet/sys/dev/usb/quirk/usb_quirk.c
  projects/vnet/sys/dev/usb/usbdevs
  projects/vnet/sys/kern/init_main.c
  projects/vnet/sys/kern/kern_event.c
  projects/vnet/sys/kern/kern_exec.c
  projects/vnet/sys/kern/kern_exit.c
  projects/vnet/sys/kern/kern_fork.c
  projects/vnet/sys/kern/kern_ntptime.c
  projects/vnet/sys/kern/kern_sig.c
  projects/vnet/sys/kern/subr_clock.c
  projects/vnet/sys/kern/subr_rtc.c
  projects/vnet/sys/net/if.c
  projects/vnet/sys/sys/event.h
  projects/vnet/sys/sys/proc.h
  projects/vnet/sys/vm/vm_fault.c
Directory Properties:
  projects/vnet/   (props changed)
  projects/vnet/sys/cddl/contrib/opensolaris/   (props changed)

Modified: projects/vnet/Makefile.inc1
==============================================================================
--- projects/vnet/Makefile.inc1	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/Makefile.inc1	Wed Jun 29 11:39:37 2016	(r302277)
@@ -549,8 +549,10 @@ TARGET_ABI=	gnueabi
 XCFLAGS+=	-isystem ${WORLDTMP}/usr/include -L${WORLDTMP}/usr/lib
 # Force using libc++ for external GCC.
 # XXX: This should be checking MK_GNUCXX == no
+.if ${X_COMPILER_VERSION} >= 40800
 XCXXFLAGS+=	-isystem ${WORLDTMP}/usr/include/c++/v1 -std=c++11 \
 		-nostdinc++ -L${WORLDTMP}/../lib/libc++
+.endif
 .else
 TARGET_ABI?=	unknown
 TARGET_TRIPLE?=	${TARGET_ARCH:C/amd64/x86_64/}-${TARGET_ABI}-freebsd11.0

Modified: projects/vnet/Makefile.libcompat
==============================================================================
--- projects/vnet/Makefile.libcompat	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/Makefile.libcompat	Wed Jun 29 11:39:37 2016	(r302277)
@@ -81,8 +81,8 @@ LIBCOMPATCFLAGS+=	-B${LIBCOMPATTMP}/usr/
 LIBCOMPATCFLAGS+=	-isystem ${LIBCOMPATTMP}/usr/include
 # Force using libc++ for external GCC.
 # XXX: This should be checking MK_GNUCXX == no
-.if ${MK_CROSS_COMPILER} == "no" || \
-    (${MK_CLANG_BOOTSTRAP} == "no" && ${MK_GCC_BOOTSTRAP} == "no")
+.if ${X_COMPILER_VERSION} >= 40800 && (${MK_CROSS_COMPILER} == "no" || \
+    (${MK_CLANG_BOOTSTRAP} == "no" && ${MK_GCC_BOOTSTRAP} == "no"))
 LIBCOMPATCXXFLAGS+=	-isystem ${LIBCOMPATTMP}/usr/include/c++/v1 -std=c++11 \
 			-nostdinc++ -L${LIBCOMPAT_OBJTREE}${.CURDIR}/lib/libc++
 .endif

Modified: projects/vnet/lib/libc/rpc/Makefile.inc
==============================================================================
--- projects/vnet/lib/libc/rpc/Makefile.inc	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/lib/libc/rpc/Makefile.inc	Wed Jun 29 11:39:37 2016	(r302277)
@@ -33,7 +33,7 @@ CFLAGS+= -I${LIBC_SRCTOP}/rpc
 
 CLEANFILES+= crypt_clnt.c crypt_xdr.c crypt.h
 
-RPCDIR= ${DESTDIR}/usr/include/rpcsvc
+RPCDIR= ${SRCTOP}/include/rpcsvc
 RPCGEN= RPCGEN_CPP=${CPP:Q} rpcgen -C
 
 crypt_clnt.c: ${RPCDIR}/crypt.x crypt.h

Modified: projects/vnet/lib/libc/tests/ssp/Makefile
==============================================================================
--- projects/vnet/lib/libc/tests/ssp/Makefile	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/lib/libc/tests/ssp/Makefile	Wed Jun 29 11:39:37 2016	(r302277)
@@ -1,5 +1,9 @@
 # $FreeBSD$
 
+# XXX This is a workaround to allow i386 to cross-compile on an amd64 host.
+.include <host-target.mk>
+# XXX ---
+
 .include <bsd.own.mk>
 
 NO_WERROR=
@@ -34,7 +38,17 @@ PROGS+=		h_memset
 .if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
 .if ${COMPILER_TYPE} == "clang" && ${MK_TOOLCHAIN} == "yes"
 .if ${COMPILER_VERSION} < 30500 || 30700 <= ${COMPILER_VERSION}
+
+# XXX This is a workaround to allow i386 to cross-compile on an amd64 host.
+.if ${MACHINE_CPUARCH} == ${_HOST_ARCH}
+# XXX ---
+
 PROGS+=		h_raw
+
+# XXX This is a workaround to allow i386 to cross-compile on an amd64 host.
+.endif
+# XXX ---
+
 .endif
 .endif
 .endif

Modified: projects/vnet/lib/libc/yp/Makefile.inc
==============================================================================
--- projects/vnet/lib/libc/yp/Makefile.inc	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/lib/libc/yp/Makefile.inc	Wed Jun 29 11:39:37 2016	(r302277)
@@ -9,7 +9,7 @@ CLEANFILES+=	yp.h yp_xdr.c
 
 SYM_MAPS+=	${LIBC_SRCTOP}/yp/Symbol.map
 
-RPCSRC=	${DESTDIR}/usr/include/rpcsvc/yp.x
+RPCSRC=	${SRCTOP}/include/rpcsvc/yp.x
 RPCGEN=	RPCGEN_CPP=${CPP:Q} rpcgen -C
 
 yp_xdr.c: ${RPCSRC}

Modified: projects/vnet/sbin/natd/natd.c
==============================================================================
--- projects/vnet/sbin/natd/natd.c	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/sbin/natd/natd.c	Wed Jun 29 11:39:37 2016	(r302277)
@@ -618,7 +618,7 @@ static void DoGlobal (int fd)
 	
 	if (wrote != bytes) {
 
-		if (errno == EMSGSIZE) {
+		if (errno == EMSGSIZE && mip != NULL) {
 
 			if (mip->ifMTU != -1)
 				SendNeedFragIcmp (icmpSock,

Modified: projects/vnet/share/man/man4/tcp.4
==============================================================================
--- projects/vnet/share/man/man4/tcp.4	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/share/man/man4/tcp.4	Wed Jun 29 11:39:37 2016	(r302277)
@@ -34,7 +34,7 @@
 .\"     From: @(#)tcp.4	8.1 (Berkeley) 6/5/93
 .\" $FreeBSD$
 .\"
-.Dd May 19, 2016
+.Dd June 28, 2016
 .Dt TCP 4
 .Os
 .Sh NAME
@@ -119,7 +119,7 @@ supports a number of socket options whic
 .Xr setsockopt 2
 and tested with
 .Xr getsockopt 2 :
-.Bl -tag -width ".Dv TCP_CONGESTION"
+.Bl -tag -width ".Dv TCP_FUNCTION_BLK"
 .It Dv TCP_INFO
 Information about a socket's underlying TCP session may be retrieved
 by passing the read-only option
@@ -148,6 +148,20 @@ connection.
 See
 .Xr mod_cc 4
 for details.
+.It Dv TCP_FUNCTION_BLK
+Select or query the set of functions that TCP will use for this connection.
+This allows a user to select an alternate TCP stack.
+The alternate TCP stack must already be loaded in the kernel.
+To list the available TCP stacks, see
+.Va functions_available
+in the
+.Sx MIB Variables
+section further down.
+To list the default TCP stack, see
+.Va functions_default
+in the
+.Sx MIB Variables
+section.
 .It Dv TCP_KEEPINIT
 This
 .Xr setsockopt 2
@@ -568,6 +582,10 @@ Number of times default MSS was used in 
 .It Va pmtud_blackhole_failed
 Number of connections for which retransmits continued even after MSS
 downshift.
+.It Va functions_available
+List of available TCP function blocks (TCP stacks).
+.It Va functions_default
+The default TCP function block (TCP stack).
 .El
 .Sh ERRORS
 A socket operation may fail with one of the following errors returned:
@@ -599,6 +617,10 @@ exists;
 .It Bq Er EAFNOSUPPORT
 when an attempt is made to bind or connect a socket to a multicast
 address.
+.It Bq Er EINVAL
+when trying to change TCP function blocks at an invalid point in the session;
+.It Bq Er ENOENT
+when trying to use a TCP function block that is not available;
 .El
 .Sh SEE ALSO
 .Xr getsockopt 2 ,

Modified: projects/vnet/share/man/man5/src.conf.5
==============================================================================
--- projects/vnet/share/man/man5/src.conf.5	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/share/man/man5/src.conf.5	Wed Jun 29 11:39:37 2016	(r302277)
@@ -1,7 +1,7 @@
 .\" DO NOT EDIT-- this file is automatically generated.
 .\" from FreeBSD: head/tools/build/options/makeman 292283 2015-12-15 18:42:30Z bdrewery
 .\" $FreeBSD$
-.Dd June 24, 2016
+.Dd June 28, 2016
 .Dt SRC.CONF 5
 .Os
 .Sh NAME
@@ -633,6 +633,9 @@ An alternate bootstrap tool chain must b
 .\" from FreeBSD: head/tools/build/options/WITHOUT_EXAMPLES 156938 2006-03-21 09:06:24Z ru
 Set to avoid installing examples to
 .Pa /usr/share/examples/ .
+.It Va WITH_EXTRA_TCP_STACKS
+.\" from FreeBSD: head/tools/build/options/WITH_EXTRA_TCP_STACKS 302247 2016-06-28 13:37:01Z jtl
+Set to build extra TCP stack modules.
 .It Va WITHOUT_FDT
 .\" from FreeBSD: head/tools/build/options/WITHOUT_FDT 221539 2011-05-06 19:10:27Z ru
 Set to not build Flattened Device Tree support as part of the base system.

Modified: projects/vnet/share/man/man9/Makefile
==============================================================================
--- projects/vnet/share/man/man9/Makefile	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/share/man/man9/Makefile	Wed Jun 29 11:39:37 2016	(r302277)
@@ -284,6 +284,7 @@ MAN=	accept_filter.9 \
 	sysctl_ctx_init.9 \
 	SYSINIT.9 \
 	taskqueue.9 \
+	tcp_functions.9 \
 	thread_exit.9 \
 	time.9 \
 	timeout.9 \
@@ -1734,6 +1735,8 @@ MLINKS+=taskqueue.9 TASK_INIT.9 \
 	taskqueue.9 taskqueue_start_threads_pinned.9 \
 	taskqueue.9 taskqueue_unblock.9 \
 	taskqueue.9 TIMEOUT_TASK_INIT.9
+MLINKS+=tcp_functions.9 register_tcp_functions.9 \
+	tcp_functions.9 deregister_tcp_functions.9
 MLINKS+=time.9 boottime.9 \
 	time.9 time_second.9 \
 	time.9 time_uptime.9

Copied: projects/vnet/share/man/man9/tcp_functions.9 (from r302276, head/share/man/man9/tcp_functions.9)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/vnet/share/man/man9/tcp_functions.9	Wed Jun 29 11:39:37 2016	(r302277, copy of r302276, head/share/man/man9/tcp_functions.9)
@@ -0,0 +1,285 @@
+.\"
+.\" Copyright (c) 2016 Jonathan Looney <jtl@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+.\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 28, 2016
+.Dt TCP_FUNCTIONS 9
+.Os
+.Sh NAME
+.Nm tcp_functions
+.Nd Alternate TCP Stack Framework
+.Sh SYNOPSIS
+.In netinet/tcp.h
+.In netinet/tcp_var.h
+.Ft int
+.Fn register_tcp_functions "struct tcp_function_block *blk" "int wait"
+.Ft int
+.Fn deregister_tcp_functions "struct tcp_function_block *blk"
+.Sh DESCRIPTION
+The
+.Nm
+framework allows a kernel developer to implement alternate TCP stacks.
+The alternate stacks can be compiled in the kernel or can be implemented in
+loadable kernel modules.
+This functionality is intended to encourage experimentation with the TCP stack
+and to allow alternate behaviors to be deployed for different TCP connections
+on a single system.
+.Pp
+A system administrator can set a system default stack.
+By default, all TCP connections will use the system default stack.
+Additionally, users can specify a particular stack to use on a per-connection
+basis.
+(See
+.Xr tcp 4
+for details on setting the system default stack, or selecting a specific stack
+for a given connection.)
+.Pp
+This man page treats "TCP stacks" as synonymous with "function blocks".
+This is intentional.
+A "TCP stack" is a collection of functions that implement a set of behavior.
+Therefore, an alternate "function block" defines an alternate "TCP stack".
+.Pp
+.Nm
+modules must call the
+.Fn register_tcp_functions
+function during initialization and successfully call the
+.Fn deregister_tcp_functions
+function prior to allowing the module to be unloaded.
+.Pp
+The
+.Fn register_tcp_functions
+function requests that the system add a specified function block to the system.
+.Pp
+The
+.Fn deregister_tcp_functions
+function requests that the system remove a specified function block from the
+system.
+If the call fails because sockets are still using the specified function block,
+the system will mark the function block as being in the process of being
+removed.
+This will prevent additional sockets from using the specified function block.
+However, it will not impact sockets that are already using the function block.
+.Pp
+The
+.Fa blk
+argument is a pointer to a
+.Vt "struct tcp_function_block" ,
+which is explained below (see
+.Sx Function Block Structure ) .
+The
+.Fa wait
+argument is used as the
+.Fa flags
+argument to
+.Xr malloc 9 ,
+and must be set to one of the valid values defined in that man page.
+.Ss Function Block Structure
+The
+.Fa blk argument is a pointer to a
+.Vt "struct tcp_function_block" ,
+which has the following members:
+.Bd -literal -offset indent
+struct tcp_function_block {
+	char	tfb_tcp_block_name[TCP_FUNCTION_NAME_LEN_MAX];
+	int	(*tfb_tcp_output)(struct tcpcb *);
+	void	(*tfb_tcp_do_segment)(struct mbuf *, struct tcphdr *,
+			    struct socket *, struct tcpcb *,
+			    int, int, uint8_t,
+			    int);
+	int     (*tfb_tcp_ctloutput)(struct socket *so,
+			    struct sockopt *sopt,
+			    struct inpcb *inp, struct tcpcb *tp);
+	/* Optional memory allocation/free routine */
+	void	(*tfb_tcp_fb_init)(struct tcpcb *);
+	void	(*tfb_tcp_fb_fini)(struct tcpcb *);
+	/* Optional timers, must define all if you define one */
+	int	(*tfb_tcp_timer_stop_all)(struct tcpcb *);
+	void	(*tfb_tcp_timer_activate)(struct tcpcb *,
+			    uint32_t, u_int);
+	int	(*tfb_tcp_timer_active)(struct tcpcb *, uint32_t);
+	void	(*tfb_tcp_timer_stop)(struct tcpcb *, uint32_t);
+	void	(*tfb_tcp_rexmit_tmr)(struct tcpcb *);
+	volatile uint32_t tfb_refcnt;
+	uint32_t  tfb_flags;
+};
+.Ed
+.Pp
+The
+.Va tfb_tcp_block_name
+field identifies the unique name of the TCP stack, and should be no longer than
+TCP_FUNCTION_NAME_LEN_MAX-1 characters in length.
+.Pp
+The
+.Va tfb_tcp_output ,
+.Va tfb_tcp_do_segment ,
+and
+.Va tfb_tcp_ctloutput
+fields are pointers to functions that perform the equivalent actions
+as the default
+.Fn tcp_output ,
+.Fn tcp_do_segment ,
+and
+.Fn tcp_default_ctloutput
+functions, respectively.
+Each of these function pointers must be non-NULL.
+.Pp
+If a TCP stack needs to initialize data when a socket first selects the TCP
+stack (or, when the socket is first opened), it should set a non-NULL
+pointer in the
+.Va tfb_tcp_fb_init
+field.
+Likewise, if a TCP stack needs to cleanup data when a socket stops using the
+TCP stack (or, when the socket is closed), it should set a non-NULL pointer
+in the
+.Va tfb_tcp_fb_fini
+field.
+.Pp
+If the TCP stack implements additional timers, the TCP stack should set a
+non-NULL pointer in the
+.Va tfb_tcp_timer_stop_all ,
+.Va tfb_tcp_timer_activate ,
+.Va tfb_tcp_timer_active ,
+and
+.Va tfb_tcp_timer_stop
+fields.
+These fields should all be
+.Dv NULL
+or should all contain pointers to functions.
+The
+.Va tfb_tcp_timer_activate ,
+.Va tfb_tcp_timer_active ,
+and
+.Va tfb_tcp_timer_stop
+functions will be called when the
+.Fn tcp_timer_activate ,
+.Fn tcp_timer_active ,
+and
+.Fn tcp_timer_stop
+functions, respectively, are called with a timer type other than the standard
+types.
+The functions defined by the TCP stack have the same semantics (both for
+arguments and return values) as the normal timer functions they supplement.
+.Pp
+Additionally, a stack may define its own actions to take when the retransmit
+timer fires by setting a non-NULL function pointer in the
+.Va tfb_tcp_rexmit_tmr
+field.
+This function is called very early in the process of handling a retransmit
+timer.
+However, care must be taken to ensure the retransmit timer leaves the
+TCP control block in a valid state for the remainder of the retransmit
+timer logic.
+.Pp
+The
+.Va tfb_refcnt
+and
+.Va tfb_flags
+fields are used by the kernel's TCP code and will be initialized when the
+TCP stack is registered.
+.Ss Requirements for Alternate TCP Stacks
+If the TCP stack needs to store data beyond what is stored in the default
+TCP control block, the TCP stack can initialize its own per-connection storage.
+The
+.Va t_fb_ptr
+field in the
+.Vt "struct tcpcb"
+control block structure has been reserved to hold a pointer to this
+per-connection storage.
+If the TCP stack uses this alternate storage, it should understand that the
+value of the
+.Va t_fb_ptr
+pointer may not be initialized to
+.Dv NULL .
+Therefore, it should use a
+.Va tfb_tcp_fb_init
+function to initialize this field.
+Additionally, it should use a
+.Va tfb_tcp_fb_fini
+function to deallocate storage when the socket is closed.
+.Pp
+It is understood that alternate TCP stacks may keep different sets of data.
+However, in order to ensure that data is available to both the user and the
+rest of the system in a standardized format, alternate TCP stacks must
+update all fields in the TCP control block to the greatest extent practical.
+.Sh RETURN VALUES
+The
+.Fn register_tcp_functions
+and
+.Fn deregister_tcp_functions
+functions return zero on success and non-zero on failure.
+In particular, the
+.Fn deregister_tcp_functions
+will return
+.Er EBUSY
+until no more connections are using the specified TCP stack.
+A module calling
+.Fn deregister_tcp_functions
+must be prepared to wait until all connections have stopped using the
+specified TCP stack.
+.Sh ERRORS
+The
+.Fn register_tcp_functions
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Any of the members of the
+.Fa blk
+argument are set incorrectly.
+.It Bq Er ENOMEM
+The function could not allocate memory for its internal data.
+.It Bq Er EALREADY
+A function block is already registered with the same name.
+.El
+The
+.Fn deregister_tcp_functions
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+The
+.Fa blk
+argument references the kernel's compiled-in default function block.
+.It Bq Er EBUSY
+The function block is still in use by one or more sockets, or is defined as
+the current default function block.
+.It Bq Er ENOENT
+The
+.Fa blk
+argument references a function block that is not currently registered.
+.Sh SEE ALSO
+.Xr malloc 9 ,
+.Xr tcp 4
+.Sh HISTORY
+This framework first appeared in
+.Fx 11.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+framework was written by
+.An Randall Stewart Aq Mt rrs@FreeBSD.org .
+.Pp
+This manual page was written by
+.An Jonathan Looney Aq Mt jtl@FreeBSD.org .

Modified: projects/vnet/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c
==============================================================================
--- projects/vnet/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c	Wed Jun 29 11:39:37 2016	(r302277)
@@ -238,10 +238,15 @@ int zfs_disable_dup_eviction = 0;
 uint64_t zfs_arc_average_blocksize = 8 * 1024; /* 8KB */
 u_int zfs_arc_free_target = 0;
 
+/* Absolute min for arc min / max is 16MB. */
+static uint64_t arc_abs_min = 16 << 20;
+
 static int sysctl_vfs_zfs_arc_free_target(SYSCTL_HANDLER_ARGS);
 static int sysctl_vfs_zfs_arc_meta_limit(SYSCTL_HANDLER_ARGS);
+static int sysctl_vfs_zfs_arc_max(SYSCTL_HANDLER_ARGS);
+static int sysctl_vfs_zfs_arc_min(SYSCTL_HANDLER_ARGS);
 
-#ifdef _KERNEL
+#if defined(__FreeBSD__) && defined(_KERNEL)
 static void
 arc_free_target_init(void *unused __unused)
 {
@@ -255,10 +260,10 @@ TUNABLE_QUAD("vfs.zfs.arc_meta_limit", &
 TUNABLE_QUAD("vfs.zfs.arc_meta_min", &zfs_arc_meta_min);
 TUNABLE_INT("vfs.zfs.arc_shrink_shift", &zfs_arc_shrink_shift);
 SYSCTL_DECL(_vfs_zfs);
-SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, arc_max, CTLFLAG_RDTUN, &zfs_arc_max, 0,
-    "Maximum ARC size");
-SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, arc_min, CTLFLAG_RDTUN, &zfs_arc_min, 0,
-    "Minimum ARC size");
+SYSCTL_PROC(_vfs_zfs, OID_AUTO, arc_max, CTLTYPE_U64 | CTLFLAG_RWTUN,
+    0, sizeof(uint64_t), sysctl_vfs_zfs_arc_max, "QU", "Maximum ARC size");
+SYSCTL_PROC(_vfs_zfs, OID_AUTO, arc_min, CTLTYPE_U64 | CTLFLAG_RWTUN,
+    0, sizeof(uint64_t), sysctl_vfs_zfs_arc_min, "QU", "Minimum ARC size");
 SYSCTL_UQUAD(_vfs_zfs, OID_AUTO, arc_average_blocksize, CTLFLAG_RDTUN,
     &zfs_arc_average_blocksize, 0,
     "ARC average blocksize");
@@ -884,7 +889,7 @@ struct arc_buf_hdr {
 	l1arc_buf_hdr_t		b_l1hdr;
 };
 
-#ifdef _KERNEL
+#if defined(__FreeBSD__) && defined(_KERNEL)
 static int
 sysctl_vfs_zfs_arc_meta_limit(SYSCTL_HANDLER_ARGS)
 {
@@ -902,6 +907,70 @@ sysctl_vfs_zfs_arc_meta_limit(SYSCTL_HAN
 	arc_meta_limit = val;
 	return (0);
 }
+
+static int
+sysctl_vfs_zfs_arc_max(SYSCTL_HANDLER_ARGS)
+{
+	uint64_t val;
+	int err;
+
+	val = zfs_arc_max;
+	err = sysctl_handle_64(oidp, &val, 0, req);
+	if (err != 0 || req->newptr == NULL)
+		return (err);
+
+	if (val < arc_abs_min || val > kmem_size())
+		return (EINVAL);
+	if (val < arc_c_min)
+		return (EINVAL);
+	if (zfs_arc_meta_limit > 0 && val < zfs_arc_meta_limit)
+		return (EINVAL);
+
+	arc_c_max = val;
+
+	arc_c = arc_c_max;
+        arc_p = (arc_c >> 1);
+
+	if (zfs_arc_meta_limit == 0) {
+		/* limit meta-data to 1/4 of the arc capacity */
+		arc_meta_limit = arc_c_max / 4;
+	}
+
+	/* if kmem_flags are set, lets try to use less memory */
+	if (kmem_debugging())
+		arc_c = arc_c / 2;
+
+	zfs_arc_max = arc_c;
+
+	return (0);
+}
+
+static int
+sysctl_vfs_zfs_arc_min(SYSCTL_HANDLER_ARGS)
+{
+	uint64_t val;
+	int err;
+
+	val = zfs_arc_min;
+	err = sysctl_handle_64(oidp, &val, 0, req);
+	if (err != 0 || req->newptr == NULL)
+		return (err);
+
+	if (val < arc_abs_min || val > arc_c_max)
+		return (EINVAL);
+
+	arc_c_min = val;
+
+	if (zfs_arc_meta_min == 0)
+                arc_meta_min = arc_c_min / 2;
+
+	if (arc_c < arc_c_min)
+                arc_c = arc_c_min;
+
+	zfs_arc_min = arc_c_min;
+
+	return (0);
+}
 #endif
 
 static arc_buf_t *arc_eviction_list;
@@ -5385,8 +5454,8 @@ arc_init(void)
 	arc_c = MIN(arc_c, vmem_size(heap_arena, VMEM_ALLOC | VMEM_FREE) / 8);
 #endif
 #endif	/* illumos */
-	/* set min cache to 1/32 of all memory, or 16MB, whichever is more */
-	arc_c_min = MAX(arc_c / 4, 16 << 20);
+	/* set min cache to 1/32 of all memory, or arc_abs_min, whichever is more */
+	arc_c_min = MAX(arc_c / 4, arc_abs_min);
 	/* set max to 1/2 of all memory, or all but 1GB, whichever is more */
 	if (arc_c * 8 >= 1 << 30)
 		arc_c_max = (arc_c * 8) - (1 << 30);
@@ -5407,11 +5476,11 @@ arc_init(void)
 #ifdef _KERNEL
 	/*
 	 * Allow the tunables to override our calculations if they are
-	 * reasonable (ie. over 16MB)
+	 * reasonable.
 	 */
-	if (zfs_arc_max > 16 << 20 && zfs_arc_max < kmem_size())
+	if (zfs_arc_max > arc_abs_min && zfs_arc_max < kmem_size())
 		arc_c_max = zfs_arc_max;
-	if (zfs_arc_min > 16 << 20 && zfs_arc_min <= arc_c_max)
+	if (zfs_arc_min > arc_abs_min && zfs_arc_min <= arc_c_max)
 		arc_c_min = zfs_arc_min;
 #endif
 

Modified: projects/vnet/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_pool.c
==============================================================================
--- projects/vnet/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_pool.c	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_pool.c	Wed Jun 29 11:39:37 2016	(r302277)
@@ -49,8 +49,8 @@
 #include <sys/dsl_userhold.h>
 
 #if defined(__FreeBSD__) && defined(_KERNEL)
-#include <sys/sysctl.h>
 #include <sys/types.h>
+#include <sys/sysctl.h>
 #endif
 
 /*

Modified: projects/vnet/sys/dev/cxgbe/t4_main.c
==============================================================================
--- projects/vnet/sys/dev/cxgbe/t4_main.c	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/sys/dev/cxgbe/t4_main.c	Wed Jun 29 11:39:37 2016	(r302277)
@@ -8981,12 +8981,12 @@ toe_capability(struct vi_info *vi, int e
 		 * port has never been UP'd administratively.
 		 */
 		if (!(vi->flags & VI_INIT_DONE)) {
-			rc = cxgbe_init_synchronized(vi);
+			rc = vi_full_init(vi);
 			if (rc)
 				return (rc);
 		}
 		if (!(pi->vi[0].flags & VI_INIT_DONE)) {
-			rc = cxgbe_init_synchronized(&pi->vi[0]);
+			rc = vi_full_init(&pi->vi[0]);
 			if (rc)
 				return (rc);
 		}

Modified: projects/vnet/sys/dev/cxgbe/tom/t4_listen.c
==============================================================================
--- projects/vnet/sys/dev/cxgbe/tom/t4_listen.c	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/sys/dev/cxgbe/tom/t4_listen.c	Wed Jun 29 11:39:37 2016	(r302277)
@@ -532,7 +532,7 @@ t4_listen_start(struct toedev *tod, stru
 #endif
 
 	/*
-	 * Find a running VI with IFCAP_TOE (4 or 6).  We'll use the first
+	 * Find an initialized VI with IFCAP_TOE (4 or 6).  We'll use the first
 	 * such VI's queues to send the passive open and receive the reply to
 	 * it.
 	 *
@@ -543,7 +543,7 @@ t4_listen_start(struct toedev *tod, stru
 	for_each_port(sc, i) {
 		pi = sc->port[i];
 		for_each_vi(pi, v, vi) {
-			if (vi->ifp->if_drv_flags & IFF_DRV_RUNNING &&
+			if (vi->flags & VI_INIT_DONE &&
 			    vi->ifp->if_capenable & IFCAP_TOE)
 				goto found;
 		}

Modified: projects/vnet/sys/dev/usb/quirk/usb_quirk.c
==============================================================================
--- projects/vnet/sys/dev/usb/quirk/usb_quirk.c	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/sys/dev/usb/quirk/usb_quirk.c	Wed Jun 29 11:39:37 2016	(r302277)
@@ -200,6 +200,7 @@ static struct usb_quirk_entry usb_quirks
 	USB_QUIRK(FREECOM, DVD, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI),
 	USB_QUIRK(FUJIPHOTO, MASS0100, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI_I,
 	    UQ_MSC_FORCE_PROTO_ATAPI, UQ_MSC_NO_RS_CLEAR_UA, UQ_MSC_NO_SYNC_CACHE),
+	USB_QUIRK(GARMIN, FORERUNNER230, 0x0000, 0xffff, UQ_MSC_NO_INQUIRY),
 	USB_QUIRK(GENESYS, GL641USB2IDE, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB,
 	    UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_FORCE_SHORT_INQ,
 	    UQ_MSC_NO_START_STOP, UQ_MSC_IGNORE_RESIDUE, UQ_MSC_NO_SYNC_CACHE),

Modified: projects/vnet/sys/dev/usb/usbdevs
==============================================================================
--- projects/vnet/sys/dev/usb/usbdevs	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/sys/dev/usb/usbdevs	Wed Jun 29 11:39:37 2016	(r302277)
@@ -2151,6 +2151,7 @@ product FUJITSU AH_F401U	0x105b	AH-F401U
 product FUJITSUSIEMENS SCR	0x0009	Fujitsu-Siemens SCR USB Reader
 
 /* Garmin products */
+product GARMIN FORERUNNER230	0x086d	ForeRunner 230
 product GARMIN IQUE_3600	0x0004	iQue 3600
 
 /* Gemalto products */

Modified: projects/vnet/sys/kern/init_main.c
==============================================================================
--- projects/vnet/sys/kern/init_main.c	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/sys/kern/init_main.c	Wed Jun 29 11:39:37 2016	(r302277)
@@ -482,7 +482,7 @@ proc0_init(void *dummy __unused)
 	p->p_flag = P_SYSTEM | P_INMEM | P_KPROC;
 	p->p_flag2 = 0;
 	p->p_state = PRS_NORMAL;
-	knlist_init_mtx(&p->p_klist, &p->p_mtx);
+	p->p_klist = knlist_alloc(&p->p_mtx);
 	STAILQ_INIT(&p->p_ktr);
 	p->p_nice = NZERO;
 	/* pid_max cannot be greater than PID_MAX */

Modified: projects/vnet/sys/kern/kern_event.c
==============================================================================
--- projects/vnet/sys/kern/kern_event.c	Wed Jun 29 11:06:13 2016	(r302276)
+++ projects/vnet/sys/kern/kern_event.c	Wed Jun 29 11:39:37 2016	(r302277)
@@ -227,14 +227,33 @@ SYSCTL_UINT(_kern, OID_AUTO, kq_calloutm
 #define KQ_NOTOWNED(kq) do {						\
 	mtx_assert(&(kq)->kq_lock, MA_NOTOWNED);			\
 } while (0)
-#define KN_LIST_LOCK(kn) do {						\
-	if (kn->kn_knlist != NULL)					\
-		kn->kn_knlist->kl_lock(kn->kn_knlist->kl_lockarg);	\
-} while (0)
-#define KN_LIST_UNLOCK(kn) do {						\
-	if (kn->kn_knlist != NULL) 					\
-		kn->kn_knlist->kl_unlock(kn->kn_knlist->kl_lockarg);	\
-} while (0)
+
+static struct knlist *
+kn_list_lock(struct knote *kn)
+{
+	struct knlist *knl;
+
+	knl = kn->kn_knlist;
+	if (knl != NULL)
+		knl->kl_lock(knl->kl_lockarg);
+	return (knl);
+}
+
+static void
+kn_list_unlock(struct knlist *knl)
+{
+	bool do_free;
+
+	if (knl == NULL)
+		return;
+	do_free = knl->kl_autodestroy && knlist_empty(knl);
+	knl->kl_unlock(knl->kl_lockarg);
+	if (do_free) {
+		knlist_destroy(knl);
+		free(knl, M_KQUEUE);
+	}
+}
+
 #define	KNL_ASSERT_LOCK(knl, islocked) do {				\
 	if (islocked)							\
 		KNL_ASSERT_LOCKED(knl);				\
@@ -350,16 +369,16 @@ static int
 filt_procattach(struct knote *kn)
 {
 	struct proc *p;
-	int immediate;
 	int error;
+	bool exiting, immediate;
 
-	immediate = 0;
+	exiting = immediate = false;
 	p = pfind(kn->kn_id);
 	if (p == NULL && (kn->kn_sfflags & NOTE_EXIT)) {
 		p = zpfind(kn->kn_id);
-		immediate = 1;
+		exiting = true;
 	} else if (p != NULL && (p->p_flag & P_WEXIT)) {
-		immediate = 1;
+		exiting = true;
 	}
 
 	if (p == NULL)
@@ -380,8 +399,8 @@ filt_procattach(struct knote *kn)
 		kn->kn_flags &= ~EV_FLAG2;
 		kn->kn_data = kn->kn_sdata;		/* ppid */
 		kn->kn_fflags = NOTE_CHILD;
-                kn->kn_sfflags &= ~NOTE_EXIT;
-		immediate = 1; /* Force immediate activation of child note. */
+		kn->kn_sfflags &= ~(NOTE_EXIT | NOTE_EXEC | NOTE_FORK);
+		immediate = true; /* Force immediate activation of child note. */
 	}
 	/*
 	 * Internal flag indicating registration done by kernel (for other than
@@ -391,8 +410,7 @@ filt_procattach(struct knote *kn)
 		kn->kn_flags &= ~EV_FLAG1;
 	}
 
-	if (immediate == 0)
-		knlist_add(&p->p_klist, kn, 1);
+	knlist_add(p->p_klist, kn, 1);
 
 	/*
 	 * Immediately activate any child notes or, in the case of a zombie
@@ -400,7 +418,7 @@ filt_procattach(struct knote *kn)
 	 * case where the target process, e.g. a child, dies before the kevent
 	 * is registered.
 	 */
-	if (immediate && filt_proc(kn, NOTE_EXIT))
+	if (immediate || (exiting && filt_proc(kn, NOTE_EXIT)))
 		KNOTE_ACTIVATE(kn, 0);
 
 	PROC_UNLOCK(p);
@@ -420,10 +438,8 @@ filt_procattach(struct knote *kn)
 static void
 filt_procdetach(struct knote *kn)
 {
-	struct proc *p;
 
-	p = kn->kn_ptr.p_proc;
-	knlist_remove(&p->p_klist, kn, 0);
+	knlist_remove(kn->kn_knlist, kn, 0);
 	kn->kn_ptr.p_proc = NULL;
 }
 
@@ -444,8 +460,6 @@ filt_proc(struct knote *kn, long hint)
 
 	/* Process is gone, so flag the event as finished. */
 	if (event == NOTE_EXIT) {
-		if (!(kn->kn_status & KN_DETACHED))
-			knlist_remove_inevent(&p->p_klist, kn);
 		kn->kn_flags |= EV_EOF | EV_ONESHOT;
 		kn->kn_ptr.p_proc = NULL;
 		if (kn->kn_fflags & NOTE_EXIT)
@@ -479,12 +493,6 @@ knote_fork(struct knlist *list, int pid)
 	list->kl_lock(list->kl_lockarg);
 
 	SLIST_FOREACH(kn, &list->kl_list, kn_selnext) {
-		/*
-		 * XXX - Why do we skip the kn if it is _INFLUX?  Does this
-		 * mean we will not properly wake up some notes?
-		 */
-		if ((kn->kn_status & KN_INFLUX) == KN_INFLUX)
-			continue;
 		kq = kn->kn_kq;
 		KQ_LOCK(kq);
 		if ((kn->kn_status & (KN_INFLUX | KN_SCAN)) == KN_INFLUX) {
@@ -525,7 +533,8 @@ knote_fork(struct knlist *list, int pid)
 		 */
 		kev.ident = pid;
 		kev.filter = kn->kn_filter;
-		kev.flags = kn->kn_flags | EV_ADD | EV_ENABLE | EV_ONESHOT | EV_FLAG2;
+		kev.flags = kn->kn_flags | EV_ADD | EV_ENABLE | EV_ONESHOT |
+		    EV_FLAG2;
 		kev.fflags = kn->kn_sfflags;
 		kev.data = kn->kn_id;		/* parent */
 		kev.udata = kn->kn_kevent.udata;/* preserve udata */
@@ -1137,6 +1146,7 @@ kqueue_register(struct kqueue *kq, struc
 	struct filterops *fops;
 	struct file *fp;
 	struct knote *kn, *tkn;
+	struct knlist *knl;
 	cap_rights_t rights;
 	int error, filt, event;
 	int haskqglobal, filedesc_unlock;
@@ -1146,6 +1156,7 @@ kqueue_register(struct kqueue *kq, struc
 
 	fp = NULL;
 	kn = NULL;
+	knl = NULL;
 	error = 0;
 	haskqglobal = 0;
 	filedesc_unlock = 0;
@@ -1300,7 +1311,7 @@ findkn:
 				knote_drop(kn, td);
 				goto done;
 			}
-			KN_LIST_LOCK(kn);
+			knl = kn_list_lock(kn);
 			goto done_ev_add;
 		} else {
 			/* No matching knote and the EV_ADD flag is not set. */
@@ -1331,7 +1342,7 @@ findkn:
 	 */
 	kn->kn_status |= KN_INFLUX | KN_SCAN;
 	KQ_UNLOCK(kq);
-	KN_LIST_LOCK(kn);
+	knl = kn_list_lock(kn);
 	kn->kn_kevent.udata = kev->udata;
 	if (!fops->f_isfd && fops->f_touch != NULL) {
 		fops->f_touch(kn, kev, EVENT_REGISTER);
@@ -1365,7 +1376,7 @@ done_ev_add:
 	    KN_ACTIVE)
 		knote_enqueue(kn);
 	kn->kn_status &= ~(KN_INFLUX | KN_SCAN);
-	KN_LIST_UNLOCK(kn);
+	kn_list_unlock(knl);
 	KQ_UNLOCK_FLUX(kq);
 
 done:
@@ -1535,6 +1546,7 @@ kqueue_scan(struct kqueue *kq, int maxev
 {
 	struct kevent *kevp;
 	struct knote *kn, *marker;
+	struct knlist *knl;
 	sbintime_t asbt, rsbt;
 	int count, error, haskqglobal, influx, nkev, touch;
 
@@ -1660,7 +1672,7 @@ retry:
 			KQ_UNLOCK(kq);
 			if ((kn->kn_status & KN_KQUEUE) == KN_KQUEUE)
 				KQ_GLOBAL_LOCK(&kq_global, haskqglobal);
-			KN_LIST_LOCK(kn);
+			knl = kn_list_lock(kn);
 			if (kn->kn_fop->f_event(kn, 0) == 0) {
 				KQ_LOCK(kq);
 				KQ_GLOBAL_UNLOCK(&kq_global, haskqglobal);
@@ -1668,7 +1680,7 @@ retry:
 				    ~(KN_QUEUED | KN_ACTIVE | KN_INFLUX |
 				    KN_SCAN);
 				kq->kq_count--;
-				KN_LIST_UNLOCK(kn);
+				kn_list_unlock(knl);
 				influx = 1;
 				continue;
 			}
@@ -1697,7 +1709,7 @@ retry:
 				TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe);
 			
 			kn->kn_status &= ~(KN_INFLUX | KN_SCAN);
-			KN_LIST_UNLOCK(kn);
+			kn_list_unlock(knl);
 			influx = 1;
 		}
 
@@ -2062,7 +2074,8 @@ knlist_add(struct knlist *knl, struct kn
 }
 
 static void
-knlist_remove_kq(struct knlist *knl, struct knote *kn, int knlislocked, int kqislocked)
+knlist_remove_kq(struct knlist *knl, struct knote *kn, int knlislocked,
+    int kqislocked)
 {
 	KASSERT(!(!!kqislocked && !knlislocked), ("kq locked w/o knl locked"));
 	KNL_ASSERT_LOCK(knl, knlislocked);
@@ -2075,7 +2088,7 @@ knlist_remove_kq(struct knlist *knl, str
 	SLIST_REMOVE(&knl->kl_list, kn, knote, kn_selnext);
 	kn->kn_knlist = NULL;
 	if (!knlislocked)
-		knl->kl_unlock(knl->kl_lockarg);
+		kn_list_unlock(knl);
 	if (!kqislocked)
 		KQ_LOCK(kn->kn_kq);
 	kn->kn_status |= KN_DETACHED;
@@ -2093,17 +2106,6 @@ knlist_remove(struct knlist *knl, struct
 	knlist_remove_kq(knl, kn, islocked, 0);
 }
 
-/*
- * remove knote from the specified knlist while in f_event handler.
- */
-void
-knlist_remove_inevent(struct knlist *knl, struct knote *kn)
-{
-
-	knlist_remove_kq(knl, kn, 1,
-	    (kn->kn_status & KN_HASKQLOCK) == KN_HASKQLOCK);
-}
-
 int
 knlist_empty(struct knlist *knl)
 {
@@ -2202,6 +2204,7 @@ knlist_init(struct knlist *knl, void *lo
 	else
 		knl->kl_assert_unlocked = kl_assert_unlocked;
 
+	knl->kl_autodestroy = 0;
 	SLIST_INIT(&knl->kl_list);
 }
 
@@ -2212,6 +2215,16 @@ knlist_init_mtx(struct knlist *knl, stru
 	knlist_init(knl, lock, NULL, NULL, NULL, NULL);
 }
 
+struct knlist *
+knlist_alloc(struct mtx *lock)
+{
+	struct knlist *knl;
+
+	knl = malloc(sizeof(struct knlist), M_KQUEUE, M_WAITOK);
+	knlist_init_mtx(knl, lock);
+	return (knl);
+}
+
 void
 knlist_init_rw_reader(struct knlist *knl, struct rwlock *lock)
 {
@@ -2237,6 +2250,18 @@ knlist_destroy(struct knlist *knl)
 	SLIST_INIT(&knl->kl_list);
 }
 
+void
+knlist_detach(struct knlist *knl)
+{
+
+	KNL_ASSERT_LOCKED(knl);
+	knl->kl_autodestroy = 1;
+	if (knlist_empty(knl)) {
+		knlist_destroy(knl);
+		free(knl, M_KQUEUE);
+	}
+}
+
 /*
  * Even if we are locked, we may need to drop the lock to allow any influx
  * knotes time to "settle".
@@ -2247,6 +2272,7 @@ knlist_cleardel(struct knlist *knl, stru
 	struct knote *kn, *kn2;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201606291139.u5TBdbN4080092>