summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/fs/sockfs/sockcommon.c16
-rw-r--r--usr/src/uts/common/fs/sockfs/sockcommon_sops.c29
-rw-r--r--usr/src/uts/common/fs/sockfs/sockcommon_subr.c55
-rw-r--r--usr/src/uts/common/io/ksocket/ksocket.c14
-rw-r--r--usr/src/uts/common/io/ksocket/ksocket_impl.h8
-rw-r--r--usr/src/uts/common/sys/ksocket.h53
-rw-r--r--usr/src/uts/common/sys/socketvar.h15
7 files changed, 168 insertions, 22 deletions
diff --git a/usr/src/uts/common/fs/sockfs/sockcommon.c b/usr/src/uts/common/fs/sockfs/sockcommon.c
index 87e29b21ae..edcb41951c 100644
--- a/usr/src/uts/common/fs/sockfs/sockcommon.c
+++ b/usr/src/uts/common/fs/sockfs/sockcommon.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
* Copyright 2017 Sebastian Wiedenroth
*/
@@ -457,16 +458,16 @@ sonode_constructor(void *buf, void *cdrarg, int kmflags)
vp->v_data = so;
vn_setops(vp, socket_vnodeops);
- so->so_priv = NULL;
+ so->so_priv = NULL;
so->so_oobmsg = NULL;
so->so_proto_handle = NULL;
- so->so_peercred = NULL;
+ so->so_peercred = NULL;
so->so_rcv_queued = 0;
- so->so_rcv_q_head = NULL;
- so->so_rcv_q_last_head = NULL;
+ so->so_rcv_q_head = NULL;
+ so->so_rcv_q_last_head = NULL;
so->so_rcv_head = NULL;
so->so_rcv_last_head = NULL;
so->so_rcv_wanted = 0;
@@ -504,6 +505,9 @@ sonode_constructor(void *buf, void *cdrarg, int kmflags)
cv_init(&so->so_copy_cv, NULL, CV_DEFAULT, NULL);
cv_init(&so->so_closing_cv, NULL, CV_DEFAULT, NULL);
+ so->so_krecv_cb = NULL;
+ so->so_krecv_arg = NULL;
+
return (0);
}
@@ -657,6 +661,10 @@ sonode_fini(struct sonode *so)
if (so->so_filter_top != NULL)
sof_sonode_cleanup(so);
+ /* Clean up any remnants of krecv callbacks */
+ so->so_krecv_cb = NULL;
+ so->so_krecv_arg = NULL;
+
ASSERT(list_is_empty(&so->so_acceptq_list));
ASSERT(list_is_empty(&so->so_acceptq_defer));
ASSERT(!list_link_active(&so->so_acceptq_node));
diff --git a/usr/src/uts/common/fs/sockfs/sockcommon_sops.c b/usr/src/uts/common/fs/sockfs/sockcommon_sops.c
index 5a8e1897ab..0e02bbbabb 100644
--- a/usr/src/uts/common/fs/sockfs/sockcommon_sops.c
+++ b/usr/src/uts/common/fs/sockfs/sockcommon_sops.c
@@ -24,7 +24,7 @@
*/
/*
- * Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2015, Joyent, Inc. All rights reserved.
* Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
*/
@@ -1325,6 +1325,26 @@ so_queue_msg_impl(struct sonode *so, mblk_t *mp,
}
}
+ mutex_enter(&so->so_lock);
+ if (so->so_krecv_cb != NULL) {
+ boolean_t cont;
+ so_krecv_f func = so->so_krecv_cb;
+ void *arg = so->so_krecv_arg;
+
+ mutex_exit(&so->so_lock);
+ cont = func(so, mp, msg_size, flags & MSG_OOB, arg);
+ mutex_enter(&so->so_lock);
+ if (cont == B_TRUE) {
+ space_left = so->so_rcvbuf;
+ } else {
+ so->so_rcv_queued = so->so_rcvlowat;
+ *errorp = ENOSPC;
+ space_left = -1;
+ }
+ goto done_unlock;
+ }
+ mutex_exit(&so->so_lock);
+
if (flags & MSG_OOB) {
so_queue_oob(so, mp, msg_size);
mutex_enter(&so->so_lock);
@@ -1615,6 +1635,13 @@ so_recvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop,
return (ENOTCONN);
}
+ mutex_enter(&so->so_lock);
+ if (so->so_krecv_cb != NULL) {
+ mutex_exit(&so->so_lock);
+ return (EOPNOTSUPP);
+ }
+ mutex_exit(&so->so_lock);
+
if (msg->msg_flags & MSG_PEEK)
msg->msg_flags &= ~MSG_WAITALL;
diff --git a/usr/src/uts/common/fs/sockfs/sockcommon_subr.c b/usr/src/uts/common/fs/sockfs/sockcommon_subr.c
index 957c8f93b4..ab9c479af3 100644
--- a/usr/src/uts/common/fs/sockfs/sockcommon_subr.c
+++ b/usr/src/uts/common/fs/sockfs/sockcommon_subr.c
@@ -24,6 +24,7 @@
*/
/*
* Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
*/
#include <sys/types.h>
@@ -2276,9 +2277,9 @@ so_tpi_fallback(struct sonode *so, struct cred *cr)
fbfunc = sp->sp_smod_info->smod_proto_fallback_func;
/*
- * Cannot fallback if the socket has active filters
+ * Cannot fallback if the socket has active filters or a krecv callback.
*/
- if (so->so_filter_active > 0)
+ if (so->so_filter_active > 0 || so->so_krecv_cb != NULL)
return (EINVAL);
switch (so->so_family) {
@@ -2456,3 +2457,53 @@ out:
return (error);
}
+
+int
+so_krecv_set(sonode_t *so, so_krecv_f cb, void *arg)
+{
+ int ret;
+
+ if (cb == NULL && arg != NULL)
+ return (EINVAL);
+
+ SO_BLOCK_FALLBACK(so, so_krecv_set(so, cb, arg));
+
+ mutex_enter(&so->so_lock);
+ if (so->so_state & SS_FALLBACK_COMP) {
+ mutex_exit(&so->so_lock);
+ SO_UNBLOCK_FALLBACK(so);
+ return (ENOTSUP);
+ }
+
+ ret = so_lock_read(so, 0);
+ VERIFY(ret == 0);
+ /*
+ * Other consumers may actually care about getting extant data delivered
+ * to them, when they come along, they should figure out the best API
+ * for that.
+ */
+ so_rcv_flush(so);
+
+ so->so_krecv_cb = cb;
+ so->so_krecv_arg = arg;
+
+ so_unlock_read(so);
+ mutex_exit(&so->so_lock);
+ SO_UNBLOCK_FALLBACK(so);
+
+ return (0);
+}
+
+void
+so_krecv_unblock(sonode_t *so)
+{
+ mutex_enter(&so->so_lock);
+ VERIFY(so->so_krecv_cb != NULL);
+
+ so->so_rcv_queued = 0;
+ (void) so_check_flow_control(so);
+ /*
+ * so_check_flow_control() always drops so->so_lock, so we won't
+ * need to drop it ourselves.
+ */
+}
diff --git a/usr/src/uts/common/io/ksocket/ksocket.c b/usr/src/uts/common/io/ksocket/ksocket.c
index a3cd9dfbb1..3ce44cce55 100644
--- a/usr/src/uts/common/io/ksocket/ksocket.c
+++ b/usr/src/uts/common/io/ksocket/ksocket.c
@@ -22,7 +22,7 @@
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, Joyent, Inc. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
*/
#include <sys/file.h>
@@ -932,3 +932,15 @@ ksocket_rele(ksocket_t ks)
cv_signal(&so->so_closing_cv);
}
}
+
+int
+ksocket_krecv_set(ksocket_t ks, ksocket_krecv_f cb, void *arg)
+{
+ return (so_krecv_set(KSTOSO(ks), (so_krecv_f)cb, arg));
+}
+
+void
+ksocket_krecv_unblock(ksocket_t ks)
+{
+ return (so_krecv_unblock(KSTOSO(ks)));
+}
diff --git a/usr/src/uts/common/io/ksocket/ksocket_impl.h b/usr/src/uts/common/io/ksocket/ksocket_impl.h
index ac5251540f..2b685008e3 100644
--- a/usr/src/uts/common/io/ksocket/ksocket_impl.h
+++ b/usr/src/uts/common/io/ksocket/ksocket_impl.h
@@ -22,11 +22,17 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2015, Joyent, Inc.
*/
#ifndef _INET_KSOCKET_KSOCKET_IMPL_H
#define _INET_KSOCKET_KSOCKET_IMPL_H
+/*
+ * Note that if this relationship ever changes, the logic in ksocket_krecv_set
+ * must be updated and we must maintain local state about this on whatever the
+ * new ksocket object is.
+ */
#define KSTOSO(ks) ((struct sonode *)(ks))
#define SOTOKS(so) ((ksocket_t)(uintptr_t)(so))
@@ -45,7 +51,7 @@
#define __KSOCKET_EV_cantrecvmore KSOCKET_EV_CANTRECVMORE
#define __KSOCKET_EV_error KSOCKET_EV_ERROR
-#define KSOCKET_CALLBACK(so, cbfn, arg) \
+#define KSOCKET_CALLBACK(so, cbfn, arg) \
if ((so)->so_ksock_callbacks.ksock_cb_##cbfn != NULL) { \
(*(so)->so_ksock_callbacks.ksock_cb_##cbfn)(SOTOKS(so), \
__KSOCKET_EV_##cbfn, (so)->so_ksock_cb_arg, (arg)); \
diff --git a/usr/src/uts/common/sys/ksocket.h b/usr/src/uts/common/sys/ksocket.h
index 5d8827f1ae..abf6bccfa5 100644
--- a/usr/src/uts/common/sys/ksocket.h
+++ b/usr/src/uts/common/sys/ksocket.h
@@ -21,6 +21,7 @@
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
*/
#ifndef _SYS_KSOCKET_H_
@@ -83,45 +84,71 @@ typedef struct ksocket_callbacks {
#define KSOCKET_SLEEP SOCKET_SLEEP
#define KSOCKET_NOSLEEP SOCKET_NOSLEEP
-extern int ksocket_socket(ksocket_t *, int, int, int, int, struct cred *);
-extern int ksocket_bind(ksocket_t, struct sockaddr *, socklen_t,
+extern int ksocket_socket(ksocket_t *, int, int, int, int, struct cred *);
+extern int ksocket_bind(ksocket_t, struct sockaddr *, socklen_t,
struct cred *);
-extern int ksocket_listen(ksocket_t, int, struct cred *);
-extern int ksocket_accept(ksocket_t, struct sockaddr *, socklen_t *,
+extern int ksocket_listen(ksocket_t, int, struct cred *);
+extern int ksocket_accept(ksocket_t, struct sockaddr *, socklen_t *,
ksocket_t *, struct cred *);
-extern int ksocket_connect(ksocket_t, struct sockaddr *, socklen_t,
+extern int ksocket_connect(ksocket_t, struct sockaddr *, socklen_t,
struct cred *);
-extern int ksocket_send(ksocket_t, void *, size_t, int, size_t *,
+extern int ksocket_send(ksocket_t, void *, size_t, int, size_t *,
struct cred *);
extern int ksocket_sendto(ksocket_t, void *, size_t, int,
struct sockaddr *, socklen_t, size_t *, struct cred *);
-extern int ksocket_sendmsg(ksocket_t, struct nmsghdr *, int, size_t *,
+extern int ksocket_sendmsg(ksocket_t, struct nmsghdr *, int, size_t *,
struct cred *);
extern int ksocket_sendmblk(ksocket_t, struct nmsghdr *, int,
struct msgb **, struct cred *);
-extern int ksocket_recv(ksocket_t, void *, size_t, int, size_t *,
+extern int ksocket_recv(ksocket_t, void *, size_t, int, size_t *,
struct cred *);
extern int ksocket_recvfrom(ksocket_t, void *, size_t, int,
struct sockaddr *, socklen_t *, size_t *, struct cred *);
extern int ksocket_recvmsg(ksocket_t, struct nmsghdr *, int, size_t *,
struct cred *);
extern int ksocket_shutdown(ksocket_t, int, struct cred *);
-extern int ksocket_setsockopt(ksocket_t, int, int, const void *, int,
+extern int ksocket_setsockopt(ksocket_t, int, int, const void *, int,
struct cred *);
-extern int ksocket_getsockopt(ksocket_t, int, int, void *, int *,
+extern int ksocket_getsockopt(ksocket_t, int, int, void *, int *,
struct cred *);
-extern int ksocket_getpeername(ksocket_t, struct sockaddr *, socklen_t *,
+extern int ksocket_getpeername(ksocket_t, struct sockaddr *, socklen_t *,
struct cred *);
-extern int ksocket_getsockname(ksocket_t, struct sockaddr *, socklen_t *,
+extern int ksocket_getsockname(ksocket_t, struct sockaddr *, socklen_t *,
struct cred *);
extern int ksocket_ioctl(ksocket_t, int, intptr_t, int *, struct cred *);
extern int ksocket_spoll(ksocket_t, int, short, short *, struct cred *);
extern int ksocket_setcallbacks(ksocket_t, ksocket_callbacks_t *, void *,
struct cred *);
-extern int ksocket_close(ksocket_t, struct cred *);
+extern int ksocket_close(ksocket_t, struct cred *);
extern void ksocket_hold(ksocket_t);
extern void ksocket_rele(ksocket_t);
+/*
+ * These functions allow an alternative way for a ksocket to directly
+ * receive data when it arrives in sockfs rather than having it queued
+ * in a socket buffer that it must separately poll. The use of this
+ * results in no data being queued in sockfs.
+ *
+ * When the receive function receives data, it is responsible for always
+ * consuming all of the data. The return value of the callback function
+ * is used to indicate flow control and backpressure (similar to
+ * mac_tx(9E)). If, after processing the data, additional data can be
+ * received and processed, then the callback function should return
+ * B_TRUE. Otherwise it should return B_FALSE. This will result in the
+ * lower level socket interfaces (e.g. TCP) understanding that
+ * backpressure has been asserted (as though the sockfs buffer is full).
+ *
+ * Once whatever conditions that caused the callback function to assert
+ * that it needed to assert flow control are done, then it must call
+ * ksocket_krecv_unblock() to allow the flow to continue. If the receive
+ * callback ever returns B_FALSE there will generally be no additional
+ * data received until this is called.
+ */
+typedef boolean_t (*ksocket_krecv_f)(ksocket_t, struct msgb *, size_t, int,
+ void *);
+extern int ksocket_krecv_set(ksocket_t, ksocket_krecv_f, void *);
+extern void ksocket_krecv_unblock(ksocket_t);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/sys/socketvar.h b/usr/src/uts/common/sys/socketvar.h
index ef2bc77f74..93090dbfa2 100644
--- a/usr/src/uts/common/sys/socketvar.h
+++ b/usr/src/uts/common/sys/socketvar.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Joyent, Inc.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
@@ -103,6 +104,7 @@ struct sockaddr_ux {
typedef struct sonodeops sonodeops_t;
typedef struct sonode sonode_t;
+typedef boolean_t (*so_krecv_f)(sonode_t *, mblk_t *, size_t, int, void *);
struct sodirect_s;
@@ -245,6 +247,10 @@ struct sonode {
struct sof_instance *so_filter_top; /* top of stack */
struct sof_instance *so_filter_bottom; /* bottom of stack */
clock_t so_filter_defertime; /* time when deferred */
+
+ /* Kernel direct receive callbacks */
+ so_krecv_f so_krecv_cb; /* recv callback */
+ void *so_krecv_arg; /* recv cb arg */
};
#define SO_HAVE_DATA(so) \
@@ -949,6 +955,15 @@ extern struct sonode *socreate(struct sockparams *, int, int, int, int,
extern int so_copyin(const void *, void *, size_t, int);
extern int so_copyout(const void *, void *, size_t, int);
+/*
+ * Functions to manipulate the use of direct receive callbacks. This should not
+ * be used outside of sockfs and ksocket. These are generally considered a use
+ * once interface for a socket and will cause all outstanding data on the socket
+ * to be flushed.
+ */
+extern int so_krecv_set(sonode_t *, so_krecv_f, void *);
+extern void so_krecv_unblock(sonode_t *);
+
#endif
/*