diff options
author | Stepan Zastupov <stepan.zastupov@gmail.com> | 2011-10-02 23:44:03 +0400 |
---|---|---|
committer | Stepan Zastupov <stepan.zastupov@gmail.com> | 2011-10-02 23:44:03 +0400 |
commit | 3076c25a759075dcc052165713ce638ecf989184 (patch) | |
tree | 3fba102d58c1d0d8c8e32cdc8d2a46f013bcbc46 | |
parent | ed22c7109fc5dd9e1b7a5d0333bdc7ad2718e2ab (diff) | |
download | illumos-joyent-3076c25a759075dcc052165713ce638ecf989184.tar.gz |
1056 ksocket doesn't support AF_UNIX
Reviewed by: Gordon Ross <gordon.w.ross@gmail.com>
Reviewed by: Garrett D'Amore <garrett.damore@gmail.com>
Approved by: Eric Schrock <eric.schrock@delphix.com>
-rw-r--r-- | usr/src/uts/common/io/ksocket/ksocket.c | 142 | ||||
-rw-r--r-- | usr/src/uts/common/sys/ksocket.h | 2 |
2 files changed, 143 insertions, 1 deletions
diff --git a/usr/src/uts/common/io/ksocket/ksocket.c b/usr/src/uts/common/io/ksocket/ksocket.c index 4100f049d7..49ca6f0475 100644 --- a/usr/src/uts/common/io/ksocket/ksocket.c +++ b/usr/src/uts/common/io/ksocket/ksocket.c @@ -20,6 +20,7 @@ */ /* + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -30,6 +31,7 @@ #include <sys/sysmacros.h> #include <sys/filio.h> /* FIO* ioctls */ #include <sys/sockio.h> /* SIOC* ioctls */ +#include <sys/poll_impl.h> #include <sys/cmn_err.h> #include <sys/ksocket.h> #include <io/ksocket/ksocket_impl.h> @@ -54,7 +56,7 @@ ksocket_socket(ksocket_t *ksp, int domain, int type, int protocol, int flags, /* All Solaris components should pass a cred for this operation. */ ASSERT(cr != NULL); - if (domain == AF_NCA || domain == AF_UNIX) + if (domain == AF_NCA) return (EAFNOSUPPORT); ASSERT(flags == KSOCKET_SLEEP || flags == KSOCKET_NOSLEEP); @@ -717,6 +719,144 @@ ksocket_ioctl(ksocket_t ks, int cmd, intptr_t arg, int *rvalp, struct cred *cr) return (rval); } +/* + * Wait for an input event, similar to t_kspoll(). + * Ideas and code borrowed from ../devpoll.c + * Basically, setup just enough poll data structures so + * we can block on a CV until timeout or pollwakeup(). + */ +int +ksocket_spoll(ksocket_t ks, int timo, short events, short *revents, + struct cred *cr) +{ + struct sonode *so; + pollhead_t *php, *php2; + polldat_t *pdp; + pollcache_t *pcp; + int error; + clock_t expires = 0; + clock_t rval; + + /* All Solaris components should pass a cred for this operation. */ + ASSERT(cr != NULL); + ASSERT(curthread->t_pollcache == NULL); + + if (revents == NULL) + return (EINVAL); + if (!KSOCKET_VALID(ks)) + return (ENOTSOCK); + so = KSTOSO(ks); + + /* + * Check if there are any events already pending. + * If we're not willing to block, (timo == 0) then + * pass "anyyet">0 to socket_poll so it can skip + * some work. Othewise pass "anyyet"=0 and if + * there are no events pending, it will fill in + * the pollhead pointer we need for pollwakeup(). + * + * XXX - pollrelock() logic needs to know which + * which pollcache lock to grab. It'd be a + * cleaner solution if we could pass pcp as + * an arguement in VOP_POLL interface instead + * of implicitly passing it using thread_t + * struct. On the other hand, changing VOP_POLL + * interface will require all driver/file system + * poll routine to change. May want to revisit + * the tradeoff later. + */ + php = NULL; + *revents = 0; + pcp = pcache_alloc(); + pcache_create(pcp, 1); + + mutex_enter(&pcp->pc_lock); + curthread->t_pollcache = pcp; + error = socket_poll(so, (short)events, (timo == 0), + revents, &php); + curthread->t_pollcache = NULL; + mutex_exit(&pcp->pc_lock); + + if (error != 0 || *revents != 0 || timo == 0) + goto out; + + /* + * Need to block. Did not get *revents, so the + * php should be non-NULL, but let's verify. + * Also compute when our sleep expires. + */ + if (php == NULL) { + error = EIO; + goto out; + } + if (timo > 0) + expires = ddi_get_lbolt() + + MSEC_TO_TICK_ROUNDUP(timo); + + /* + * Setup: pollhead -> polldat -> pollcache + * needed for pollwakeup() + * pdp should be freed by pcache_destroy + */ + pdp = kmem_zalloc(sizeof (*pdp), KM_SLEEP); + pdp->pd_fd = 0; + pdp->pd_events = events; + pdp->pd_pcache = pcp; + pcache_insert_fd(pcp, pdp, 1); + pollhead_insert(php, pdp); + pdp->pd_php = php; + + mutex_enter(&pcp->pc_lock); + while (!(so->so_state & SS_CLOSING)) { + pcp->pc_flag = 0; + + /* Ditto pcp comment above. */ + curthread->t_pollcache = pcp; + error = socket_poll(so, (short)events, 0, + revents, &php2); + curthread->t_pollcache = NULL; + ASSERT(php2 == php); + + if (error != 0 || *revents != 0) + break; + + if (pcp->pc_flag & T_POLLWAKE) + continue; + + if (timo == -1) { + rval = cv_wait_sig(&pcp->pc_cv, &pcp->pc_lock); + } else { + rval = cv_timedwait_sig(&pcp->pc_cv, &pcp->pc_lock, + expires); + } + if (rval <= 0) { + if (rval == 0) + error = EINTR; + break; + } + } + mutex_exit(&pcp->pc_lock); + + if (pdp->pd_php != NULL) { + pollhead_delete(pdp->pd_php, pdp); + pdp->pd_php = NULL; + pdp->pd_fd = NULL; + } + + /* + * pollwakeup() may still interact with this pollcache. Wait until + * it is done. + */ + mutex_enter(&pcp->pc_no_exit); + ASSERT(pcp->pc_busy >= 0); + while (pcp->pc_busy > 0) + cv_wait(&pcp->pc_busy_cv, &pcp->pc_no_exit); + mutex_exit(&pcp->pc_no_exit); +out: + pcache_destroy(pcp); + return (error); +} + int ksocket_sendmblk(ksocket_t ks, struct nmsghdr *msg, int flags, mblk_t **mpp, cred_t *cr) diff --git a/usr/src/uts/common/sys/ksocket.h b/usr/src/uts/common/sys/ksocket.h index df15b12c08..dfe25eec76 100644 --- a/usr/src/uts/common/sys/ksocket.h +++ b/usr/src/uts/common/sys/ksocket.h @@ -19,6 +19,7 @@ * CDDL HEADER END */ /* + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -113,6 +114,7 @@ extern int ksocket_getpeername(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 *); |