--- 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++;