diff options
-rw-r--r-- | usr/src/uts/common/brand/lx/os/lx_syscall.c | 15 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/sys/lx_socket.h | 10 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/sys/lx_syscalls.h | 3 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/syscall/lx_socket.c | 163 |
4 files changed, 182 insertions, 9 deletions
diff --git a/usr/src/uts/common/brand/lx/os/lx_syscall.c b/usr/src/uts/common/brand/lx/os/lx_syscall.c index ed0ccc4cb7..5a8f9322a0 100644 --- a/usr/src/uts/common/brand/lx/os/lx_syscall.c +++ b/usr/src/uts/common/brand/lx/os/lx_syscall.c @@ -23,6 +23,7 @@ * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2018 Joyent, Inc. + * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. */ #include <sys/kmem.h> @@ -564,7 +565,7 @@ lx_sysent_t lx_sysent32[] = { {"access", lx_access, 0, 2}, /* 33 */ {"nice", lx_nice, 0, 1}, /* 34 */ {"ftime", NULL, NOSYS_OBSOLETE, 0}, /* 35 */ - {"sync", lx_sync, 0, 0}, /* 36 */ + {"sync", lx_sync, 0, 0}, /* 36 */ {"kill", lx_kill, 0, 2}, /* 37 */ {"rename", lx_rename, 0, 2}, /* 38 */ {"mkdir", lx_mkdir, 0, 2}, /* 39 */ @@ -607,7 +608,7 @@ lx_sysent_t lx_sysent32[] = { {"getrlimit", lx_oldgetrlimit, 0, 2}, /* 76 */ {"getrusage", lx_getrusage, 0, 2}, /* 77 */ {"gettimeofday", lx_gettimeofday, 0, 2}, /* 78 */ - {"settimeofday", NULL, 0, 2}, /* 79 */ + {"settimeofday", NULL, 0, 2}, /* 79 */ {"getgroups16", NULL, 0, 2}, /* 80 */ {"setgroups16", NULL, 0, 2}, /* 81 */ {"select", NULL, NOSYS_OBSOLETE, 0}, /* 82 */ @@ -869,7 +870,7 @@ lx_sysent_t lx_sysent32[] = { {"pwritev", lx_pwritev32, 0, 5}, /* 334 */ {"rt_tgsigqueueinfo", NULL, 0, 4}, /* 335 */ {"perf_event_open", NULL, NOSYS_NULL, 0}, /* 336 */ - {"recvmmsg", NULL, NOSYS_NULL, 0}, /* 337 */ + {"recvmmsg", lx_recvmmsg, 0, 5}, /* 337 */ {"fanotify_init", NULL, NOSYS_NULL, 0}, /* 338 */ {"fanotify_mark", NULL, NOSYS_NULL, 0}, /* 339 */ {"prlimit64", lx_prlimit64, 0, 4}, /* 340 */ @@ -877,7 +878,7 @@ lx_sysent_t lx_sysent32[] = { {"open_by_handle_at", NULL, NOSYS_NULL, 0}, /* 342 */ {"clock_adjtime", NULL, NOSYS_NULL, 0}, /* 343 */ {"syncfs", lx_syncfs, 0, 1}, /* 344 */ - {"sendmmsg", NULL, NOSYS_NULL, 0}, /* 345 */ + {"sendmmsg", lx_sendmmsg, 0, 4}, /* 345 */ {"setns", NULL, NOSYS_NULL, 0}, /* 346 */ {"process_vm_readv", NULL, NOSYS_NULL, 0}, /* 347 */ {"process_vm_writev", NULL, NOSYS_NULL, 0}, /* 348 */ @@ -1196,9 +1197,9 @@ lx_sysent_t lx_sysent64[] = { {"inotify_init1", NULL, 0, 1}, /* 294 */ {"preadv", lx_preadv, 0, 4}, /* 295 */ {"pwritev", lx_pwritev, 0, 4}, /* 296 */ - {"rt_tgsigqueueinfo", NULL, 0, 4}, /* 297 */ + {"rt_tgsigqueueinfo", NULL, 0, 4}, /* 297 */ {"perf_event_open", NULL, NOSYS_NULL, 0}, /* 298 */ - {"recvmmsg", NULL, NOSYS_NULL, 0}, /* 299 */ + {"recvmmsg", lx_recvmmsg, 0, 5}, /* 299 */ {"fanotify_init", NULL, NOSYS_NULL, 0}, /* 300 */ {"fanotify_mark", NULL, NOSYS_NULL, 0}, /* 301 */ {"prlimit64", lx_prlimit64, 0, 4}, /* 302 */ @@ -1206,7 +1207,7 @@ lx_sysent_t lx_sysent64[] = { {"open_by_handle_at", NULL, NOSYS_NULL, 0}, /* 304 */ {"clock_adjtime", NULL, NOSYS_NULL, 0}, /* 305 */ {"syncfs", lx_syncfs, 0, 1}, /* 306 */ - {"sendmmsg", NULL, NOSYS_NULL, 0}, /* 307 */ + {"sendmmsg", lx_sendmmsg, 0, 4}, /* 307 */ {"setns", NULL, NOSYS_NULL, 0}, /* 309 */ {"getcpu", lx_getcpu, 0, 3}, /* 309 */ {"process_vm_readv", NULL, NOSYS_NULL, 0}, /* 310 */ diff --git a/usr/src/uts/common/brand/lx/sys/lx_socket.h b/usr/src/uts/common/brand/lx/sys/lx_socket.h index eb9826eebe..99489e4d13 100644 --- a/usr/src/uts/common/brand/lx/sys/lx_socket.h +++ b/usr/src/uts/common/brand/lx/sys/lx_socket.h @@ -22,6 +22,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2016 Joyent, Inc. + * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. */ #ifndef _SYS_LX_SOCKET_H @@ -403,6 +404,10 @@ typedef struct lx_msghdr { int msg_flags; /* flags on received message */ } lx_msghdr_t; +typedef struct lx_mmsghdr { + lx_msghdr_t msg_hdr; /* message header */ + unsigned int msg_len; /* no. of bytes transmitted */ +} lx_mmsghdr_t; #if defined(_LP64) @@ -416,6 +421,11 @@ typedef struct lx_msghdr32 { int32_t msg_flags; /* flags on received message */ } lx_msghdr32_t; +typedef struct lx_mmsghdr32 { + lx_msghdr32_t msg_hdr; /* message header */ + unsigned int msg_len; /* no. of bytes transmitted */ +} lx_mmsghdr32_t; + #endif typedef struct lx_sockaddr_in6 { diff --git a/usr/src/uts/common/brand/lx/sys/lx_syscalls.h b/usr/src/uts/common/brand/lx/sys/lx_syscalls.h index ad6a0e13b4..78fbf6e0a8 100644 --- a/usr/src/uts/common/brand/lx/sys/lx_syscalls.h +++ b/usr/src/uts/common/brand/lx/sys/lx_syscalls.h @@ -23,6 +23,7 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2018 Joyent, Inc. + * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. */ #ifndef _SYS_LINUX_SYSCALLS_H @@ -191,6 +192,7 @@ extern long lx_readv(); extern long lx_reboot(); extern long lx_recv(); extern long lx_recvmsg(); +extern long lx_recvmmsg(); extern long lx_recvfrom(); extern long lx_rename(); extern long lx_renameat(); @@ -209,6 +211,7 @@ extern long lx_sched_yield(); extern long lx_select(); extern long lx_send(); extern long lx_sendmsg(); +extern long lx_sendmmsg(); extern long lx_sendto(); extern long lx_set_robust_list(); extern long lx_set_thread_area(); diff --git a/usr/src/uts/common/brand/lx/syscall/lx_socket.c b/usr/src/uts/common/brand/lx/syscall/lx_socket.c index e961abdac1..a95e220ea2 100644 --- a/usr/src/uts/common/brand/lx/syscall/lx_socket.c +++ b/usr/src/uts/common/brand/lx/syscall/lx_socket.c @@ -23,6 +23,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2018 Joyent, Inc. + * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. */ #include <sys/errno.h> @@ -2103,6 +2104,120 @@ noiov: return (res); } +long +lx_recvmmsg(int sock, void *msg, uint_t vlen, int flags, timespec_t *timeoutp) +{ + hrtime_t deadline = 0; + uint_t rcvd = 0; + long ret = 0; + boolean_t waitforone; + + waitforone = ((flags & LX_MSG_WAITFORONE) != 0); + flags &= ~LX_MSG_WAITFORONE; + + /* + * We want to limit the work that a thread calling recvmmsg() can + * perform in the kernel so that it cannot accrue too high a priority. + * Artificially capping vlen means that the thread will return to + * userspace after processing at most IOV_MAX messages, giving the + * system a chance to reset the thread priority. + * + * Linux does not cap vlen here and recvmmsg() is expected to return + * once vlen messages have been received, a timeout occurs, or if an + * error is encountered; the artificial cap adds another case. + * + * It is possible that returning "early" in this emulation will + * cause problems with some applications however a properly written + * recvmmsg() consumer should consume only the received datagrams + * and try again if it wants more. This may need revisiting in the + * future. + */ + if (vlen > IOV_MAX) + vlen = IOV_MAX; + + if (timeoutp != NULL) { + timespec_t timeout; + uhrtime_t utime = (uhrtime_t)gethrtime(); + + if (get_udatamodel() == DATAMODEL_NATIVE) { + if (copyin(timeoutp, &timeout, sizeof (timestruc_t))) + return (set_errno(EFAULT)); + } else { + timestruc32_t timeout32; + if (copyin(timeoutp, &timeout32, + sizeof (timestruc32_t))) + return (set_errno(EFAULT)); + timeout.tv_sec = (time_t)timeout32.tv_sec; + timeout.tv_nsec = timeout32.tv_nsec; + } + + if (itimerspecfix(&timeout)) + return (set_errno(EINVAL)); + + /* + * Make sure that deadline will not overflow. itimerspecfix() + * has already checked for negative values and too big a value + * in tv_nsec + */ + if (timeout.tv_sec >= HRTIME_MAX / NANOSEC) + return (set_errno(EINVAL)); + + utime += timeout.tv_sec * NANOSEC; + utime += timeout.tv_nsec; + + if (utime > HRTIME_MAX) + return (set_errno(EINVAL)); + + deadline = (hrtime_t)utime; + } + + for (rcvd = 0; rcvd < vlen; rcvd++) { + uint_t *ptr; + + if (get_udatamodel() == DATAMODEL_NATIVE) { + lx_mmsghdr_t *hdr = (lx_mmsghdr_t *)msg; + hdr += rcvd; + ret = lx_recvmsg(sock, (lx_msghdr_t *)hdr, flags); + ptr = &hdr->msg_len; + } else { + lx_mmsghdr32_t *hdr = (lx_mmsghdr32_t *)msg; + hdr += rcvd; + ret = lx_recvmsg(sock, (lx_msghdr32_t *)hdr, flags); + ptr = &hdr->msg_len; + } + if (ttolwp(curthread)->lwp_errno != 0) + break; + copyout(&ret, ptr, sizeof (*ptr)); + /* + * If MSG_WAITFORONE is set, set MSG_DONTWAIT after the + * first packet has been received. + */ + if (waitforone) { + flags |= LX_MSG_DONTWAIT; + waitforone = B_FALSE; + } + /* + * The Linux man page documents the timeout option as + * only being checked after each datagram is received. + * The man page does not document ETIMEDOUT as a return + * code so we do not set an errno. + */ + if (deadline > 0 && gethrtime() >= deadline) + break; + } + + if (rcvd > 0) { + /* + * Any error code is deliberately discarded if any message + * was successfully received. + */ + ttolwp(curthread)->lwp_errno = 0; + return (rcvd); + } + + return (ret); +} + /* * Custom version of socket_sendmsg for error-handling overrides. */ @@ -2442,6 +2557,50 @@ lx_sendmsg(int sock, void *msg, int flags) return (res); } +long +lx_sendmmsg(int sock, void *msg, uint_t vlen, int flags) +{ + long ret = 0; + uint_t sent = 0; + + /* + * Linux caps vlen to UIO_MAXIOV (1024). + */ + if (vlen > IOV_MAX) + vlen = IOV_MAX; + + if (get_udatamodel() == DATAMODEL_NATIVE) { + lx_mmsghdr_t *hdr = msg; + + for (sent = 0; sent < vlen; sent++, hdr++) { + ret = lx_sendmsg(sock, (lx_msghdr_t *)hdr, flags); + if (ttolwp(curthread)->lwp_errno != 0) + break; + copyout(&ret, &hdr->msg_len, sizeof (hdr->msg_len)); + } + } else { + lx_mmsghdr32_t *hdr = msg; + + for (sent = 0; sent < vlen; sent++, hdr++) { + ret = lx_sendmsg(sock, (lx_msghdr32_t *)hdr, flags); + if (ttolwp(curthread)->lwp_errno != 0) + break; + copyout(&ret, &hdr->msg_len, sizeof (hdr->msg_len)); + } + } + + if (sent > 0) { + /* + * Any error code is deliberately discarded if any message + * was successfully sent. + */ + ttolwp(curthread)->lwp_errno = 0; + return (sent); + } + + return (ret); +} + /* * Linux socket option type definitions * @@ -4318,8 +4477,8 @@ static struct { lx_sendmsg, 3, /* sendmsg */ lx_recvmsg, 3, /* recvmsg */ lx_accept4, 4, /* accept4 */ - NULL, 5, /* recvmmsg */ - NULL, 4 /* sendmmsg */ + lx_recvmmsg, 5, /* recvmmsg */ + lx_sendmmsg, 4 /* sendmmsg */ }; long |