diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/fs/sockfs/sockcommon.c | 16 | ||||
-rw-r--r-- | usr/src/uts/common/fs/sockfs/sockcommon_sops.c | 29 | ||||
-rw-r--r-- | usr/src/uts/common/fs/sockfs/sockcommon_subr.c | 55 | ||||
-rw-r--r-- | usr/src/uts/common/io/ksocket/ksocket.c | 14 | ||||
-rw-r--r-- | usr/src/uts/common/io/ksocket/ksocket_impl.h | 8 | ||||
-rw-r--r-- | usr/src/uts/common/sys/ksocket.h | 53 | ||||
-rw-r--r-- | usr/src/uts/common/sys/socketvar.h | 15 |
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 /* |