Merge
authorAlasdair Lumsden <al@everycity.co.uk>
Thu, 18 Aug 2011 21:50:44 +0100
changeset 13460 f0897d43af7d
parent 13454 4f3dde088251 (current diff)
parent 13459 170f0c3a9064 (diff)
child 13468 a2ebdf6bc227
child 13473 76190e13ae25
Merge
--- a/usr/src/cmd/ls/ls.c	Tue Aug 16 17:07:16 2011 +0000
+++ b/usr/src/cmd/ls/ls.c	Thu Aug 18 21:50:44 2011 +0100
@@ -1795,6 +1795,7 @@
 	rep->lct.tv_nsec = 0;
 	rep->lmt.tv_sec = time(NULL);
 	rep->lmt.tv_nsec = 0;
+	rep->aclp = NULL;
 	rep->exttr = NULL;
 	rep->extm = NULL;
 	rep->color = NULL;
--- a/usr/src/cmd/ssh/libopenbsd-compat/common/glob.c	Tue Aug 16 17:07:16 2011 +0000
+++ b/usr/src/cmd/ssh/libopenbsd-compat/common/glob.c	Thu Aug 18 21:50:44 2011 +0100
@@ -37,18 +37,6 @@
 #include "includes.h"
 #include <ctype.h>
 
-static long
-get_arg_max(void)
-{
-#ifdef ARG_MAX
-	return(ARG_MAX);
-#elif defined(HAVE_SYSCONF) && defined(_SC_ARG_MAX)
-	return(sysconf(_SC_ARG_MAX));
-#else
-	return(256); /* XXX: arbitrary */
-#endif
-}
-
 #if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \
     !defined(GLOB_HAS_GL_MATCHC)
 
@@ -137,13 +125,21 @@
 #define	ismeta(c)	(((c)&M_QUOTE) != 0)
 
 
+#define	GLOB_LIMIT_MALLOC	65536
+#define	GLOB_LIMIT_STAT		128
+#define	GLOB_LIMIT_READDIR	16384
+
+#define	GLOB_INDEX_MALLOC	0
+#define	GLOB_INDEX_STAT		1
+#define	GLOB_INDEX_READDIR	2
+
 static int	 compare(const void *, const void *);
 static int	 g_Ctoc(const Char *, char *, u_int);
 static int	 g_lstat(Char *, struct stat *, glob_t *);
 static DIR	*g_opendir(Char *, glob_t *);
 static Char	*g_strchr(Char *, int);
 static int	 g_stat(Char *, struct stat *, glob_t *);
-static int	 glob0(const Char *, glob_t *);
+static int	 glob0(const Char *, glob_t *, size_t *);
 static int	 glob1(Char *, Char *, glob_t *, size_t *);
 static int	 glob2(Char *, Char *, Char *, Char *, Char *, Char *,
 		    glob_t *, size_t *);
@@ -152,8 +148,9 @@
 static int	 globextend(const Char *, glob_t *, size_t *);
 static const Char *
 		 globtilde(const Char *, Char *, size_t, glob_t *);
-static int	 globexp1(const Char *, glob_t *);
-static int	 globexp2(const Char *, const Char *, glob_t *, int *);
+static int	 globexp1(const Char *, glob_t *, size_t *);
+static int	 globexp2(const Char *, const Char *, glob_t *, int *,
+			  size_t *);
 static int	 match(Char *, Char *, Char *);
 #ifdef DEBUG
 static void	 qprintf(const char *, Char *);
@@ -168,6 +165,8 @@
 	const u_char *patnext;
 	int c;
 	Char *bufnext, *bufend, patbuf[MAXPATHLEN];
+	/* 0 = malloc(), 1 = stat(), 2 = readdir() */
+	static size_t limit[] = { 0, 0, 0 };
 
 	patnext = (u_char *) pattern;
 	if (!(flags & GLOB_APPEND)) {
@@ -200,9 +199,9 @@
 	*bufnext = EOS;
 
 	if (flags & GLOB_BRACE)
-		return globexp1(patbuf, pglob);
+		return globexp1(patbuf, pglob, limit);
 	else
-		return glob0(patbuf, pglob);
+		return glob0(patbuf, pglob, limit);
 }
 
 /*
@@ -211,22 +210,23 @@
  * characters
  */
 static int
-globexp1(pattern, pglob)
+globexp1(pattern, pglob, limit)
 	const Char *pattern;
 	glob_t *pglob;
+	size_t *limit;
 {
 	const Char* ptr = pattern;
 	int rv;
 
 	/* Protect a single {}, for find(1), like csh */
 	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
-		return glob0(pattern, pglob);
+		return glob0(pattern, pglob, limit);
 
 	while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
-		if (!globexp2(ptr, pattern, pglob, &rv))
+		if (!globexp2(ptr, pattern, pglob, &rv, limit))
 			return rv;
 
-	return glob0(pattern, pglob);
+	return glob0(pattern, pglob, limit);
 }
 
 
@@ -236,10 +236,11 @@
  * If it fails then it tries to glob the rest of the pattern and returns.
  */
 static int
-globexp2(ptr, pattern, pglob, rv)
+globexp2(ptr, pattern, pglob, rv, limit)
 	const Char *ptr, *pattern;
 	glob_t *pglob;
 	int *rv;
+	size_t *limit;
 {
 	int     i;
 	Char   *lm, *ls;
@@ -275,7 +276,7 @@
 
 	/* Non matching braces; just glob the pattern */
 	if (i != 0 || *pe == EOS) {
-		*rv = glob0(patbuf, pglob);
+		*rv = glob0(patbuf, pglob, limit);
 		return 0;
 	}
 
@@ -323,7 +324,7 @@
 #ifdef DEBUG
 				qprintf("globexp2:", patbuf);
 #endif
-				*rv = globexp1(patbuf, pglob);
+				*rv = globexp1(patbuf, pglob, limit);
 
 				/* move after the comma, to the next string */
 				pl = pm + 1;
@@ -416,14 +417,14 @@
  * to find no matches.
  */
 static int
-glob0(pattern, pglob)
+glob0(pattern, pglob, limit)
 	const Char *pattern;
 	glob_t *pglob;
+	size_t *limit;
 {
 	const Char *qpatnext;
 	int c, err, oldpathc;
 	Char *bufnext, patbuf[MAXPATHLEN];
-	size_t limit = 0;
 
 	qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
 	oldpathc = pglob->gl_pathc;
@@ -481,7 +482,7 @@
 	qprintf("glob0:", patbuf);
 #endif
 
-	if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0)
+	if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, limit)) != 0)
 		return(err);
 
 	/*
@@ -494,7 +495,7 @@
 		if ((pglob->gl_flags & GLOB_NOCHECK) ||
 		    ((pglob->gl_flags & GLOB_NOMAGIC) &&
 		    !(pglob->gl_flags & GLOB_MAGCHAR)))
-			return(globextend(pattern, pglob, &limit));
+			return(globextend(pattern, pglob, limit));
 		else
 			return(GLOB_NOMATCH);
 	}
@@ -512,10 +513,10 @@
 }
 
 static int
-glob1(pattern, pattern_last, pglob, limitp)
+glob1(pattern, pattern_last, pglob, limit)
 	Char *pattern, *pattern_last;
 	glob_t *pglob;
-	size_t *limitp;
+	size_t *limit;
 {
 	Char pathbuf[MAXPATHLEN];
 
@@ -524,7 +525,7 @@
 		return(0);
 	return(glob2(pathbuf, pathbuf+MAXPATHLEN-1,
 	    pathbuf, pathbuf+MAXPATHLEN-1,
-	    pattern, pattern_last, pglob, limitp));
+	    pattern, pattern_last, pglob, limit));
 }
 
 /*
@@ -534,11 +535,11 @@
  */
 static int
 glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern,
-    pattern_last, pglob, limitp)
+    pattern_last, pglob, limit)
 	Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
 	Char *pattern, *pattern_last;
 	glob_t *pglob;
-	size_t *limitp;
+	size_t *limit;
 {
 	struct stat sb;
 	Char *p, *q;
@@ -554,6 +555,14 @@
 			if (g_lstat(pathbuf, &sb, pglob))
 				return(0);
 
+			if ((pglob->gl_flags & GLOB_LIMIT) &&
+			    limit[GLOB_INDEX_STAT]++ >= GLOB_LIMIT_STAT) {
+				errno = 0;
+				*pathend++ = SEP;
+				*pathend = EOS;
+				return GLOB_NOSPACE;
+			}
+
 			if (((pglob->gl_flags & GLOB_MARK) &&
 			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
 			    (S_ISLNK(sb.st_mode) &&
@@ -565,7 +574,7 @@
 				*pathend = EOS;
 			}
 			++pglob->gl_matchc;
-			return(globextend(pathbuf, pglob, limitp));
+			return(globextend(pathbuf, pglob, limit));
 		}
 
 		/* Find end of next segment, copy tentatively to pathend. */
@@ -591,18 +600,18 @@
 			/* Need expansion, recurse. */
 			return(glob3(pathbuf, pathbuf_last, pathend,
 			    pathend_last, pattern, pattern_last,
-			    p, pattern_last, pglob, limitp));
+			    p, pattern_last, pglob, limit));
 	}
 	/* NOTREACHED */
 }
 
 static int
 glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last,
-    restpattern, restpattern_last, pglob, limitp)
+    restpattern, restpattern_last, pglob, limit)
 	Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
 	Char *pattern, *pattern_last, *restpattern, *restpattern_last;
 	glob_t *pglob;
-	size_t *limitp;
+	size_t *limit;
 {
 	register struct dirent *dp;
 	DIR *dirp;
@@ -645,6 +654,14 @@
 		register u_char *sc;
 		register Char *dc;
 
+		if ((pglob->gl_flags & GLOB_LIMIT) &&
+		    limit[GLOB_INDEX_READDIR]++ >= GLOB_LIMIT_READDIR) {
+			errno = 0;
+			*pathend++ = SEP;
+			*pathend = EOS;
+			return GLOB_NOSPACE;
+		}
+
 		/* Initial DOT must be matched literally. */
 		if (dp->d_name[0] == DOT && *pattern != DOT)
 			continue;
@@ -663,7 +680,7 @@
 			continue;
 		}
 		err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
-		    restpattern, restpattern_last, pglob, limitp);
+		    restpattern, restpattern_last, pglob, limit);
 		if (err)
 			break;
 	}
@@ -691,10 +708,10 @@
  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
  */
 static int
-globextend(path, pglob, limitp)
+globextend(path, pglob, limit)
 	const Char *path;
 	glob_t *pglob;
-	size_t *limitp;
+	size_t *limit;
 {
 	register char **pathv;
 	register int i;
@@ -724,7 +741,7 @@
 	for (p = path; *p++;)
 		;
 	len = (size_t)(p - path);
-	*limitp += len;
+	limit[GLOB_INDEX_MALLOC] += len;
 	if ((copy = malloc(len)) != NULL) {
 		if (g_Ctoc(path, copy, len)) {
 			free(copy);
@@ -733,11 +750,10 @@
 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
 	}
 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
-
 	if ((pglob->gl_flags & GLOB_LIMIT) &&
-	    newsize + *limitp >= (u_int) get_arg_max()) {
+		(newsize + limit[GLOB_INDEX_MALLOC]) >= GLOB_LIMIT_MALLOC) {
 		errno = 0;
-		return(GLOB_NOSPACE);
+		return GLOB_NOSPACE;
 	}
 
 	return(copy == NULL ? GLOB_NOSPACE : 0);
@@ -915,4 +931,3 @@
           !defined(GLOB_HAS_GL_MATCHC) */
 
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
--- a/usr/src/cmd/ssh/sftp/sftp-glob.c	Tue Aug 16 17:07:16 2011 +0000
+++ b/usr/src/cmd/ssh/sftp/sftp-glob.c	Thu Aug 18 21:50:44 2011 +0100
@@ -16,8 +16,6 @@
 
 /* $OpenBSD: sftp-glob.c,v 1.22 2006/08/03 03:34:42 deraadt Exp $ */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include "includes.h"
 
 #include <sys/types.h>
@@ -151,5 +149,5 @@
 	memset(&cur, 0, sizeof(cur));
 	cur.conn = conn;
 
-	return(glob(pattern, flags | GLOB_ALTDIRFUNC, errfunc, pglob));
+	return(glob(pattern, flags|GLOB_LIMIT|GLOB_ALTDIRFUNC, errfunc, pglob));
 }
--- a/usr/src/cmd/ssh/sftp/sftp.c	Tue Aug 16 17:07:16 2011 +0000
+++ b/usr/src/cmd/ssh/sftp/sftp.c	Thu Aug 18 21:50:44 2011 +0100
@@ -617,7 +617,7 @@
 
 	memset(&g, 0, sizeof(g));
 	debug3("Looking up %s", src);
-	if (glob(src, 0, NULL, &g)) {
+	if (glob(src, GLOB_LIMIT, NULL, &g)) {
 		error("File \"%s\" not found.", src);
 		err = -1;
 		goto out;
--- a/usr/src/man/man7p/tcp.7p	Tue Aug 16 17:07:16 2011 +0000
+++ b/usr/src/man/man7p/tcp.7p	Thu Aug 18 21:50:44 2011 +0100
@@ -1,5 +1,6 @@
 '\" te
 .\" Copyright (c) 2006, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
 .\" Copyright 1989 AT&T
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
@@ -344,6 +345,14 @@
 out and abort the connection when probing. The system default is controlled by
 the TCP ndd parameter tcp_keepalive_abort_interval. The default is eight
 minutes.
+.sp
+.LP
+socket options TCP_KEEPIDLE, TCP_KEEPCNT and TCP_KEEPINTVL are also supported
+for compatibility with other Unix Flavors. TCP_KEEPIDLE option specifies the
+interval in seconds for sending out the first keep-alive probe. TCP_KEEPCNT
+specifies the number of keep-alive probes to be sent before aborting the
+connection in the event of no response from peer. TCP_KEEPINTVL specifies the
+interval in seconds between successive keep-alive probes.
 .SH SEE ALSO
 .sp
 .LP
@@ -385,7 +394,7 @@
 \fB\fBEISCONN\fR\fR
 .ad
 .RS 17n
-.rt  
+.rt
 A \fBconnect()\fR operation was attempted on a socket on which a
 \fBconnect()\fR operation had already been performed.
 .RE
@@ -397,7 +406,7 @@
 \fB\fBETIMEDOUT\fR\fR
 .ad
 .RS 17n
-.rt  
+.rt
 A connection was dropped due to excessive retransmissions.
 .RE
 
@@ -408,7 +417,7 @@
 \fB\fBECONNRESET\fR\fR
 .ad
 .RS 17n
-.rt  
+.rt
 The remote peer forced the connection to be closed (usually because the remote
 machine has lost state information about the connection due to a crash).
 .RE
@@ -420,7 +429,7 @@
 \fB\fBECONNREFUSED\fR\fR
 .ad
 .RS 17n
-.rt  
+.rt
 The remote peer actively refused connection establishment (usually because no
 process is listening to the port).
 .RE
@@ -432,7 +441,7 @@
 \fB\fBEADDRINUSE\fR\fR
 .ad
 .RS 17n
-.rt  
+.rt
 A \fBbind()\fR operation was attempted on a socket with a network address/port
 pair that has already been bound to another socket.
 .RE
@@ -444,7 +453,7 @@
 \fB\fBEADDRNOTAVAIL\fR\fR
 .ad
 .RS 17n
-.rt  
+.rt
 A \fBbind()\fR operation was attempted on a socket with a network address for
 which no network interface exists.
 .RE
@@ -456,7 +465,7 @@
 \fB\fBEACCES\fR\fR
 .ad
 .RS 17n
-.rt  
+.rt
 A \fBbind()\fR operation was attempted with a "reserved" port number and the
 effective user \fBID\fR of the process was not the privileged user.
 .RE
@@ -468,7 +477,7 @@
 \fB\fBENOBUFS\fR\fR
 .ad
 .RS 17n
-.rt  
+.rt
 The system ran out of memory for internal data structures.
 .RE
 
--- a/usr/src/uts/common/inet/tcp.h	Tue Aug 16 17:07:16 2011 +0000
+++ b/usr/src/uts/common/inet/tcp.h	Thu Aug 18 21:50:44 2011 +0100
@@ -21,6 +21,7 @@
 /*
  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
  */
 /* Copyright (c) 1990 Mentat Inc. */
 
@@ -334,11 +335,26 @@
 	} tcp_conn;
 	uint32_t tcp_syn_rcvd_timeout;	/* How many SYN_RCVD timeout in q0 */
 
-	/* TCP Keepalive Timer members */
+	/*
+	 * TCP Keepalive Timer members.
+	 * All keepalive timer intervals are in milliseconds.
+	 */
 	int32_t	tcp_ka_last_intrvl;	/* Last probe interval */
 	timeout_id_t tcp_ka_tid;	/* Keepalive timer ID */
 	uint32_t tcp_ka_interval;	/* Keepalive interval */
+
+	/*
+	 * TCP connection is terminated if we don't hear back from the peer
+	 * for tcp_ka_abort_thres milliseconds after the first keepalive probe.
+	 * tcp_ka_rinterval is the interval in milliseconds between successive
+	 * keepalive probes. tcp_ka_cnt is the number of keepalive probes to
+	 * be sent before terminating the connection, if we don't hear back from
+	 * peer.
+	 * tcp_ka_abort_thres = tcp_ka_rinterval * tcp_ka_cnt
+	 */
+	uint32_t tcp_ka_rinterval;	/* keepalive retransmit interval */
 	uint32_t tcp_ka_abort_thres;	/* Keepalive abort threshold */
+	uint32_t tcp_ka_cnt;		/* count of keepalive probes */
 
 	int32_t	tcp_client_errno;	/* How the client screwed up */
 
--- a/usr/src/uts/common/inet/tcp/tcp.c	Tue Aug 16 17:07:16 2011 +0000
+++ b/usr/src/uts/common/inet/tcp/tcp.c	Thu Aug 18 21:50:44 2011 +0100
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011, Joyent Inc. All rights reserved.
+ * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
  */
 /* Copyright (c) 1990 Mentat Inc. */
 
@@ -2354,6 +2355,8 @@
 
 		tcp->tcp_ka_interval = tcps->tcps_keepalive_interval;
 		tcp->tcp_ka_abort_thres = tcps->tcps_keepalive_abort_interval;
+		tcp->tcp_ka_cnt = 0;
+		tcp->tcp_ka_rinterval = 0;
 
 		/*
 		 * Default value of tcp_init_cwnd is 0, so no need to set here
--- a/usr/src/uts/common/inet/tcp/tcp_opt_data.c	Tue Aug 16 17:07:16 2011 +0000
+++ b/usr/src/uts/common/inet/tcp/tcp_opt_data.c	Thu Aug 18 21:50:44 2011 +0100
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -117,6 +118,12 @@
 { TCP_KEEPALIVE_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0,
 	sizeof (int), 0	},
 
+{ TCP_KEEPIDLE, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
+
+{ TCP_KEEPCNT, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
+
+{ TCP_KEEPINTVL, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
+
 { TCP_KEEPALIVE_ABORT_THRESHOLD, IPPROTO_TCP, OA_RW, OA_RW, OP_NP, 0,
 	sizeof (int), 0	},
 
@@ -403,6 +410,25 @@
 		case TCP_KEEPALIVE_THRESHOLD:
 			*i1 = tcp->tcp_ka_interval;
 			return (sizeof (int));
+
+		/*
+		 * TCP_KEEPIDLE expects value in seconds, but
+		 * tcp_ka_interval is in milliseconds.
+		 */
+		case TCP_KEEPIDLE:
+			*i1 = tcp->tcp_ka_interval / 1000;
+			return (sizeof (int));
+		case TCP_KEEPCNT:
+			*i1 = tcp->tcp_ka_cnt;
+			return (sizeof (int));
+
+		/*
+		 * TCP_KEEPINTVL expects value in seconds, but
+		 * tcp_ka_rinterval is in milliseconds.
+		 */
+		case TCP_KEEPINTVL:
+			*i1 = tcp->tcp_ka_rinterval / 1000;
+			return (sizeof (int));
 		case TCP_KEEPALIVE_ABORT_THRESHOLD:
 			*i1 = tcp->tcp_ka_abort_thres;
 			return (sizeof (int));
@@ -682,6 +708,18 @@
 			}
 			tcp->tcp_init_cwnd = val;
 			break;
+
+		/*
+		 * TCP_KEEPIDLE is in seconds but TCP_KEEPALIVE_THRESHOLD
+		 * is in milliseconds. TCP_KEEPIDLE is introduced for
+		 * compatibility with other Unix flavors.
+		 * We can fall through TCP_KEEPALIVE_THRESHOLD logic after
+		 * converting the input to milliseconds.
+		 */
+		case TCP_KEEPIDLE:
+			*i1 *= 1000;
+			/* FALLTHRU */
+
 		case TCP_KEEPALIVE_THRESHOLD:
 			if (checkonly)
 				break;
@@ -708,6 +746,66 @@
 				}
 			}
 			break;
+
+		/*
+		 * tcp_ka_abort_thres = tcp_ka_rinterval * tcp_ka_cnt.
+		 * So setting TCP_KEEPCNT or TCP_KEEPINTVL can affect all the
+		 * three members - tcp_ka_abort_thres, tcp_ka_rinterval and
+		 * tcp_ka_cnt.
+		 */
+		case TCP_KEEPCNT:
+			if (checkonly)
+				break;
+
+			if (*i1 == 0) {
+				return (EINVAL);
+			} else if (tcp->tcp_ka_rinterval == 0) {
+				if ((tcp->tcp_ka_abort_thres / *i1) <
+				    tcp->tcp_rto_min ||
+				    (tcp->tcp_ka_abort_thres / *i1) >
+				    tcp->tcp_rto_max)
+					return (EINVAL);
+
+				tcp->tcp_ka_rinterval =
+				    tcp->tcp_ka_abort_thres / *i1;
+			} else {
+				if ((*i1 * tcp->tcp_ka_rinterval) <
+				    tcps->tcps_keepalive_abort_interval_low ||
+				    (*i1 * tcp->tcp_ka_rinterval) >
+				    tcps->tcps_keepalive_abort_interval_high)
+					return (EINVAL);
+				tcp->tcp_ka_abort_thres =
+				    (*i1 * tcp->tcp_ka_rinterval);
+			}
+			tcp->tcp_ka_cnt = *i1;
+			break;
+		case TCP_KEEPINTVL:
+			/*
+			 * TCP_KEEPINTVL is specified in seconds, but
+			 * tcp_ka_rinterval is in milliseconds.
+			 */
+
+			if (checkonly)
+				break;
+
+			if ((*i1 * 1000) < tcp->tcp_rto_min ||
+			    (*i1 * 1000) > tcp->tcp_rto_max)
+				return (EINVAL);
+
+			if (tcp->tcp_ka_cnt == 0) {
+				tcp->tcp_ka_cnt =
+				    tcp->tcp_ka_abort_thres / (*i1 * 1000);
+			} else {
+				if ((*i1 * tcp->tcp_ka_cnt * 1000) <
+				    tcps->tcps_keepalive_abort_interval_low ||
+				    (*i1 * tcp->tcp_ka_cnt * 1000) >
+				    tcps->tcps_keepalive_abort_interval_high)
+					return (EINVAL);
+				tcp->tcp_ka_abort_thres =
+				    (*i1 * tcp->tcp_ka_cnt * 1000);
+			}
+			tcp->tcp_ka_rinterval = *i1 * 1000;
+			break;
 		case TCP_KEEPALIVE_ABORT_THRESHOLD:
 			if (!checkonly) {
 				if (*i1 <
@@ -718,6 +816,8 @@
 					return (EINVAL);
 				}
 				tcp->tcp_ka_abort_thres = *i1;
+				tcp->tcp_ka_cnt = 0;
+				tcp->tcp_ka_rinterval = 0;
 			}
 			break;
 		case TCP_CORK:
--- a/usr/src/uts/common/inet/tcp/tcp_timers.c	Tue Aug 16 17:07:16 2011 +0000
+++ b/usr/src/uts/common/inet/tcp/tcp_timers.c	Thu Aug 18 21:50:44 2011 +0100
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -390,6 +391,11 @@
  * (tcp_ka_interval + tcp_ka_abort_thres) we have not heard anything,
  * kill the connection unless the keepalive abort threshold is 0.  In
  * that case, we will probe "forever."
+ * If tcp_ka_cnt and tcp_ka_rinterval are non-zero, then we do not follow
+ * the exponential backoff, but send probes tcp_ka_cnt times in regular
+ * intervals of tcp_ka_rinterval milliseconds until we hear back from peer.
+ * Kill the connection if we don't hear back from peer after tcp_ka_cnt
+ * probes are sent.
  */
 void
 tcp_keepalive_timer(void *arg)
@@ -455,7 +461,9 @@
 			if (mp != NULL) {
 				tcp_send_data(tcp, mp);
 				TCPS_BUMP_MIB(tcps, tcpTimKeepaliveProbe);
-				if (tcp->tcp_ka_last_intrvl != 0) {
+				if (tcp->tcp_ka_rinterval) {
+					firetime = tcp->tcp_ka_rinterval;
+				} else if (tcp->tcp_ka_last_intrvl != 0) {
 					int max;
 					/*
 					 * We should probe again at least
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c	Tue Aug 16 17:07:16 2011 +0000
+++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c	Thu Aug 18 21:50:44 2011 +0100
@@ -21,6 +21,9 @@
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
+/*
+ * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+ */
 
 #include <sys/cpuvar.h>
 #include <sys/types.h>
@@ -2165,7 +2168,6 @@
 	}
 }
 
-/*ARGSUSED*/
 void
 iscsit_deferred_dispatch(idm_pdu_t *rx_pdu)
 {
@@ -2188,16 +2190,8 @@
 	iscsit_conn_dispatch_hold(ict);
 	mutex_exit(&ict->ict_mutex);
 
-	if (taskq_dispatch(iscsit_global.global_dispatch_taskq,
-	    iscsit_deferred, rx_pdu, DDI_NOSLEEP) == NULL) {
-		/*
-		 * In the unlikely scenario that we couldn't get the resources
-		 * to dispatch the PDU then just drop it.
-		 */
-		idm_pdu_complete(rx_pdu, IDM_STATUS_FAIL);
-		idm_conn_event(ict->ict_ic, CE_TRANSPORT_FAIL, NULL);
-		iscsit_conn_dispatch_rele(ict);
-	}
+	taskq_dispatch_ent(iscsit_global.global_dispatch_taskq,
+	    iscsit_deferred, rx_pdu, 0, &rx_pdu->isp_tqent);
 }
 
 static void
--- a/usr/src/uts/common/netinet/tcp.h	Tue Aug 16 17:07:16 2011 +0000
+++ b/usr/src/uts/common/netinet/tcp.h	Thu Aug 18 21:50:44 2011 +0100
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
  */
 
 /*
@@ -125,6 +126,9 @@
 /* gap for expansion of ``standard'' options */
 #define	TCP_ANONPRIVBIND		0x20	/* for internal use only  */
 #define	TCP_EXCLBIND			0x21	/* for internal use only  */
+#define	TCP_KEEPIDLE			0x22
+#define	TCP_KEEPCNT			0x23
+#define	TCP_KEEPINTVL			0x24
 
 #ifdef	__cplusplus
 }
--- a/usr/src/uts/common/sys/idm/idm_impl.h	Tue Aug 16 17:07:16 2011 +0000
+++ b/usr/src/uts/common/sys/idm/idm_impl.h	Thu Aug 18 21:50:44 2011 +0100
@@ -21,6 +21,10 @@
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
+/*
+ * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+ */
+
 #ifndef	_IDM_IMPL_H_
 #define	_IDM_IMPL_H_
 
@@ -30,6 +34,7 @@
 
 #include <sys/avl.h>
 #include <sys/socket_impl.h>
+#include <sys/taskq_impl.h>
 
 /*
  * IDM lock order:
@@ -373,6 +378,9 @@
 	uint_t		isp_hdrbuflen;
 	uint_t		isp_databuflen;
 	time_t		isp_queue_time;
+
+	/* Taskq dispatching state for deferred PDU */
+	taskq_ent_t	isp_tqent;
 } idm_pdu_t;
 
 /*