usr/src/uts/common/fs/sockfs/sockvnops.c
changeset 741 40027a3621ac
parent 0 68f95e015346
child 898 64b2a371a6bd
--- a/usr/src/uts/common/fs/sockfs/sockvnops.c	Sat Oct 22 11:06:40 2005 -0700
+++ b/usr/src/uts/common/fs/sockfs/sockvnops.c	Sat Oct 22 22:50:14 2005 -0700
@@ -53,6 +53,7 @@
 #include <sys/stropts.h>
 #include <sys/stream.h>
 #include <sys/strsubr.h>
+#include <sys/strsun.h>
 #include <sys/suntpi.h>
 #include <sys/ioctl.h>
 #include <sys/sockio.h>
@@ -87,6 +88,9 @@
 
 #include <fs/sockfs/nl7c.h>
 
+#include <inet/udp_impl.h>
+#include <inet/tcp_impl.h>
+
 static int socktpi_close(struct vnode *, int, int, offset_t, struct cred *);
 static int socktpi_read(struct vnode *, struct uio *, int, struct cred *,
 	struct caller_context *);
@@ -140,6 +144,15 @@
 };
 
 /*
+ * Do direct function call to the transport layer below; this would
+ * also allow the transport to utilize read-side synchronous stream
+ * interface if necessary.  This is a /etc/system tunable that must
+ * not be modified on a running system.  By default this is enabled
+ * for performance reasons and may be disabled for debugging purposes.
+ */
+boolean_t socktpi_direct = B_TRUE;
+
+/*
  * Open routine used by socket() call. Note that vn_open checks for
  * VSOCK and fails the open (and VOP_OPEN is fs_nosys). The VSOCK check is
  * needed since VSOCK type vnodes exist in various underlying filesystems as
@@ -205,6 +218,56 @@
 
 		ASSERT(stp->sd_wrq != NULL);
 		so->so_provinfo = tpi_findprov(stp->sd_wrq);
+
+		/*
+		 * If caller is interested in doing direct function call
+		 * interface to/from transport module, probe the module
+		 * directly beneath the streamhead to see if it qualifies.
+		 *
+		 * We turn off direct interface when qualifications fail;
+		 * note that we do these checks for everything other than
+		 * the tcp acceptor case, because the acceptor inherits
+		 * the capabilities of the listener and we've already done
+		 * the checks against the listening socket.
+		 */
+		if (!(flag & SO_ACCEPTOR) && (so->so_state & SS_DIRECT)) {
+			queue_t *tq = stp->sd_wrq->q_next;
+
+			/*
+			 * SS_DIRECT is currently supported and tested
+			 * only for tcp/udp; this is the main reason to
+			 * have the following assertions.
+			 */
+			ASSERT(so->so_family == AF_INET ||
+			    so->so_family == AF_INET6);
+			ASSERT(so->so_protocol == IPPROTO_UDP ||
+			    so->so_protocol == IPPROTO_TCP ||
+			    so->so_protocol == IPPROTO_IP);
+			ASSERT(so->so_type == SOCK_DGRAM ||
+			    so->so_type == SOCK_STREAM);
+
+			/*
+			 * Abort direct call interface if the module directly
+			 * underneath the stream head is not defined with the
+			 * _D_DIRECT flag.  This could happen in the tcp or
+			 * udp case, when some other module is autopushed
+			 * above it, or for some reasons the expected module
+			 * isn't purely D_MP (which is the main requirement).
+			 */
+			if (!socktpi_direct || !(tq->q_flag & _QDIRECT) ||
+			    !(_OTHERQ(tq)->q_flag & _QDIRECT)) {
+				int rval;
+
+				/* Continue on without direct calls */
+				so->so_state &= ~SS_DIRECT;
+				if ((error = strioctl(vp, _SIOCSOCKFALLBACK,
+				    0, 0, K_TO_K, CRED(), &rval)) != 0) {
+					(void) socktpi_close(vp, flag, 1,
+					    (offset_t)0, cr);
+					return (error);
+				}
+			}
+		}
 	} else {
 		/*
 		 * While the same socket can not be reopened (unlike specfs)
@@ -436,6 +499,11 @@
 			/* Give NL7C some data */
 			nl7c_data(so, uiop);
 		}
+
+		if ((so_state & SS_DIRECT) &&
+		    canputnext(vp->v_stream->sd_wrq)) {
+			return (sostream_direct(so, uiop, NULL, cr));
+		}
 		return (strwrite(vp, uiop, cr));
 	} else {
 		/* Send T_DATA_REQ messages without MORE_flag set */
@@ -631,7 +699,7 @@
 	case I_SENDFD:
 	case I_RECVFD:
 	case I_ATMARK:
-	case SIOCPOPSOCKFS:
+	case _SIOCSOCKFALLBACK:
 		/*
 		 * These ioctls do not apply to sockets. I_FDINSERT can be
 		 * used to send M_PROTO messages without modifying the socket
@@ -639,8 +707,9 @@
 		 * descriptor passing since they assume a twisted stream.
 		 * SIOCATMARK must be used instead of I_ATMARK.
 		 *
-		 * SIOCPOPSOCKFS from an application should never be
-		 * processed. It is always generated in response to I_POP.
+		 * _SIOCSOCKFALLBACK from an application should never be
+		 * processed.  It is only generated by socktpi_open() or
+		 * in response to I_POP or I_PUSH.
 		 */
 #ifdef DEBUG
 		cmn_err(CE_WARN, "Unsupported STREAMS ioctl 0x%x on socket. "
@@ -724,6 +793,24 @@
 
 	switch (cmd) {
 	case I_PUSH:
+		if (so->so_state & SS_DIRECT) {
+			mutex_enter(&so->so_lock);
+			so_lock_single(so);
+			mutex_exit(&so->so_lock);
+
+			error = strioctl(vp, _SIOCSOCKFALLBACK, 0, 0, K_TO_K,
+			    CRED(), rvalp);
+
+			mutex_enter(&so->so_lock);
+			if (error == 0)
+				so->so_state &= ~SS_DIRECT;
+			so_unlock_single(so, SOLOCKED);
+			mutex_exit(&so->so_lock);
+
+			if (error != 0)
+				return (error);
+		}
+
 		error = strioctl(vp, cmd, arg, mode, U_TO_K, cr, rvalp);
 		if (error == 0)
 			so->so_pushcnt++;