17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52caf0dcdSrshoaib * Common Development and Distribution License (the "License").
62caf0dcdSrshoaib * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
212caf0dcdSrshoaib
227c478bd9Sstevel@tonic-gate /*
233e95bd4aSAnders Persson * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
248e935259SBryan Cantrill * Copyright 2015, Joyent, Inc. All rights reserved.
258e935259SBryan Cantrill * Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
2619581f84SAlexander Eremin * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27d865fc92SAndy Fiddaman * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
2815f90b02SGarrett D'Amore * Copyright 2022 Garrett D'Amore
2919581f84SAlexander Eremin */
30187670a0STheo Schlossnagle
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
337c478bd9Sstevel@tonic-gate #include <sys/param.h>
347c478bd9Sstevel@tonic-gate #include <sys/systm.h>
357c478bd9Sstevel@tonic-gate #include <sys/buf.h>
367c478bd9Sstevel@tonic-gate #include <sys/conf.h>
377c478bd9Sstevel@tonic-gate #include <sys/cred.h>
387c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
397c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
407c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
417c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
427c478bd9Sstevel@tonic-gate #include <sys/debug.h>
437c478bd9Sstevel@tonic-gate #include <sys/errno.h>
447c478bd9Sstevel@tonic-gate #include <sys/time.h>
457c478bd9Sstevel@tonic-gate #include <sys/file.h>
467c478bd9Sstevel@tonic-gate #include <sys/user.h>
477c478bd9Sstevel@tonic-gate #include <sys/stream.h>
487c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
497c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
5074024373Spr #include <sys/sunddi.h>
517c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
527c478bd9Sstevel@tonic-gate #include <sys/flock.h>
537c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
557c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h>
567c478bd9Sstevel@tonic-gate #include <sys/policy.h>
578e935259SBryan Cantrill #include <sys/limits.h>
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate #include <sys/socket.h>
607c478bd9Sstevel@tonic-gate #include <sys/socketvar.h>
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
637c478bd9Sstevel@tonic-gate #include <sys/inttypes.h>
647c478bd9Sstevel@tonic-gate #include <sys/systm.h>
657c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
667c478bd9Sstevel@tonic-gate #include <sys/filio.h>
677c478bd9Sstevel@tonic-gate #include <sys/sendfile.h>
687c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
697c478bd9Sstevel@tonic-gate #include <vm/seg.h>
707c478bd9Sstevel@tonic-gate #include <vm/seg_map.h>
717c478bd9Sstevel@tonic-gate #include <vm/seg_kpm.h>
720f1702c5SYu Xiangning
730f1702c5SYu Xiangning #include <fs/sockfs/sockcommon.h>
743e95bd4aSAnders Persson #include <fs/sockfs/sockfilter_impl.h>
750f1702c5SYu Xiangning #include <fs/sockfs/socktpi.h>
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate #ifdef SOCK_TEST
787c478bd9Sstevel@tonic-gate int do_useracc = 1; /* Controlled by setting SO_DEBUG to 4 */
797c478bd9Sstevel@tonic-gate #else
807c478bd9Sstevel@tonic-gate #define do_useracc 1
817c478bd9Sstevel@tonic-gate #endif /* SOCK_TEST */
827c478bd9Sstevel@tonic-gate
838cd31312SMarcel Telka extern int xnet_truncate_print;
843e95bd4aSAnders Persson
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate * Kernel component of socket creation.
877c478bd9Sstevel@tonic-gate *
887c478bd9Sstevel@tonic-gate * The socket library determines which version number to use.
897c478bd9Sstevel@tonic-gate * First the library calls this with a NULL devpath. If this fails
907c478bd9Sstevel@tonic-gate * to find a transport (using solookup) the library will look in /etc/netconfig
917c478bd9Sstevel@tonic-gate * for the appropriate transport. If one is found it will pass in the
927c478bd9Sstevel@tonic-gate * devpath for the kernel to use.
937c478bd9Sstevel@tonic-gate */
947c478bd9Sstevel@tonic-gate int
so_socket(int family,int type_w_flags,int protocol,char * devpath,int version)95187670a0STheo Schlossnagle so_socket(int family, int type_w_flags, int protocol, char *devpath,
96187670a0STheo Schlossnagle int version)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate struct sonode *so;
997c478bd9Sstevel@tonic-gate vnode_t *vp;
1007c478bd9Sstevel@tonic-gate struct file *fp;
1017c478bd9Sstevel@tonic-gate int fd;
1027c478bd9Sstevel@tonic-gate int error;
103187670a0STheo Schlossnagle int type;
1047c478bd9Sstevel@tonic-gate
105187670a0STheo Schlossnagle type = type_w_flags & SOCK_TYPE_MASK;
106a63a4ea3SKeith M Wesolowski type_w_flags &= ~SOCK_TYPE_MASK;
107a63a4ea3SKeith M Wesolowski if (type_w_flags & ~(SOCK_CLOEXEC|SOCK_NDELAY|SOCK_NONBLOCK))
108a63a4ea3SKeith M Wesolowski return (set_errno(EINVAL));
109a63a4ea3SKeith M Wesolowski
1100f1702c5SYu Xiangning if (devpath != NULL) {
1110f1702c5SYu Xiangning char *buf;
1120f1702c5SYu Xiangning size_t kdevpathlen = 0;
1137c478bd9Sstevel@tonic-gate
1140f1702c5SYu Xiangning buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1150f1702c5SYu Xiangning if ((error = copyinstr(devpath, buf,
1160f1702c5SYu Xiangning MAXPATHLEN, &kdevpathlen)) != 0) {
1170f1702c5SYu Xiangning kmem_free(buf, MAXPATHLEN);
1187c478bd9Sstevel@tonic-gate return (set_errno(error));
1197c478bd9Sstevel@tonic-gate }
1200f1702c5SYu Xiangning so = socket_create(family, type, protocol, buf, NULL,
1210f1702c5SYu Xiangning SOCKET_SLEEP, version, CRED(), &error);
1220f1702c5SYu Xiangning kmem_free(buf, MAXPATHLEN);
1237c478bd9Sstevel@tonic-gate } else {
1240f1702c5SYu Xiangning so = socket_create(family, type, protocol, NULL, NULL,
1250f1702c5SYu Xiangning SOCKET_SLEEP, version, CRED(), &error);
1267c478bd9Sstevel@tonic-gate }
1270f1702c5SYu Xiangning if (so == NULL)
1287c478bd9Sstevel@tonic-gate return (set_errno(error));
1297c478bd9Sstevel@tonic-gate
1300f1702c5SYu Xiangning /* Allocate a file descriptor for the socket */
1310f1702c5SYu Xiangning vp = SOTOV(so);
132*34793d0fSToomas Soome error = falloc(vp, FWRITE|FREAD, &fp, &fd);
133*34793d0fSToomas Soome if (error != 0) {
1340f1702c5SYu Xiangning (void) socket_close(so, 0, CRED());
1350f1702c5SYu Xiangning socket_destroy(so);
1367c478bd9Sstevel@tonic-gate return (set_errno(error));
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate /*
1407c478bd9Sstevel@tonic-gate * Now fill in the entries that falloc reserved
1417c478bd9Sstevel@tonic-gate */
142a63a4ea3SKeith M Wesolowski if (type_w_flags & SOCK_NDELAY) {
143a63a4ea3SKeith M Wesolowski so->so_state |= SS_NDELAY;
144a63a4ea3SKeith M Wesolowski fp->f_flag |= FNDELAY;
145a63a4ea3SKeith M Wesolowski }
146a63a4ea3SKeith M Wesolowski if (type_w_flags & SOCK_NONBLOCK) {
147a63a4ea3SKeith M Wesolowski so->so_state |= SS_NONBLOCK;
148a63a4ea3SKeith M Wesolowski fp->f_flag |= FNONBLOCK;
149a63a4ea3SKeith M Wesolowski }
1507c478bd9Sstevel@tonic-gate mutex_exit(&fp->f_tlock);
1517c478bd9Sstevel@tonic-gate setf(fd, fp);
152187670a0STheo Schlossnagle if ((type_w_flags & SOCK_CLOEXEC) != 0) {
153187670a0STheo Schlossnagle f_setfd(fd, FD_CLOEXEC);
154187670a0STheo Schlossnagle }
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate return (fd);
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate * Map from a file descriptor to a socket node.
1617c478bd9Sstevel@tonic-gate * Returns with the file descriptor held i.e. the caller has to
1627c478bd9Sstevel@tonic-gate * use releasef when done with the file descriptor.
1637c478bd9Sstevel@tonic-gate */
164745b2690Stz struct sonode *
getsonode(int sock,int * errorp,file_t ** fpp)1657c478bd9Sstevel@tonic-gate getsonode(int sock, int *errorp, file_t **fpp)
1667c478bd9Sstevel@tonic-gate {
1677c478bd9Sstevel@tonic-gate file_t *fp;
1687c478bd9Sstevel@tonic-gate vnode_t *vp;
1697c478bd9Sstevel@tonic-gate struct sonode *so;
1707c478bd9Sstevel@tonic-gate
1717c478bd9Sstevel@tonic-gate if ((fp = getf(sock)) == NULL) {
1727c478bd9Sstevel@tonic-gate *errorp = EBADF;
1737c478bd9Sstevel@tonic-gate eprintline(*errorp);
1747c478bd9Sstevel@tonic-gate return (NULL);
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate vp = fp->f_vnode;
1777c478bd9Sstevel@tonic-gate /* Check if it is a socket */
1787c478bd9Sstevel@tonic-gate if (vp->v_type != VSOCK) {
1797c478bd9Sstevel@tonic-gate releasef(sock);
1807c478bd9Sstevel@tonic-gate *errorp = ENOTSOCK;
1817c478bd9Sstevel@tonic-gate eprintline(*errorp);
1827c478bd9Sstevel@tonic-gate return (NULL);
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate /*
1857c478bd9Sstevel@tonic-gate * Use the stream head to find the real socket vnode.
1867c478bd9Sstevel@tonic-gate * This is needed when namefs sits above sockfs.
1877c478bd9Sstevel@tonic-gate */
1887c478bd9Sstevel@tonic-gate if (vp->v_stream) {
1897c478bd9Sstevel@tonic-gate ASSERT(vp->v_stream->sd_vnode);
1907c478bd9Sstevel@tonic-gate vp = vp->v_stream->sd_vnode;
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate so = VTOSO(vp);
1937c478bd9Sstevel@tonic-gate if (so->so_version == SOV_STREAM) {
1947c478bd9Sstevel@tonic-gate releasef(sock);
1957c478bd9Sstevel@tonic-gate *errorp = ENOTSOCK;
1967c478bd9Sstevel@tonic-gate eprintsoline(so, *errorp);
1977c478bd9Sstevel@tonic-gate return (NULL);
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate } else {
2007c478bd9Sstevel@tonic-gate so = VTOSO(vp);
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate if (fpp)
2037c478bd9Sstevel@tonic-gate *fpp = fp;
2047c478bd9Sstevel@tonic-gate return (so);
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate /*
2087c478bd9Sstevel@tonic-gate * Allocate and copyin a sockaddr.
2097c478bd9Sstevel@tonic-gate * Ensures NULL termination for AF_UNIX addresses by extending them
2107c478bd9Sstevel@tonic-gate * with one NULL byte if need be. Verifies that the length is not
2117c478bd9Sstevel@tonic-gate * excessive to prevent an application from consuming all of kernel
2127c478bd9Sstevel@tonic-gate * memory. Returns NULL when an error occurred.
2137c478bd9Sstevel@tonic-gate */
2147c478bd9Sstevel@tonic-gate static struct sockaddr *
copyin_name(struct sonode * so,struct sockaddr * name,socklen_t * namelenp,int * errorp)2157c478bd9Sstevel@tonic-gate copyin_name(struct sonode *so, struct sockaddr *name, socklen_t *namelenp,
2168cd31312SMarcel Telka int *errorp)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate char *faddr;
2197c478bd9Sstevel@tonic-gate size_t namelen = (size_t)*namelenp;
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate ASSERT(namelen != 0);
2227c478bd9Sstevel@tonic-gate if (namelen > SO_MAXARGSIZE) {
2237c478bd9Sstevel@tonic-gate *errorp = EINVAL;
2247c478bd9Sstevel@tonic-gate eprintsoline(so, *errorp);
2257c478bd9Sstevel@tonic-gate return (NULL);
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate faddr = (char *)kmem_alloc(namelen, KM_SLEEP);
2297c478bd9Sstevel@tonic-gate if (copyin(name, faddr, namelen)) {
2307c478bd9Sstevel@tonic-gate kmem_free(faddr, namelen);
2317c478bd9Sstevel@tonic-gate *errorp = EFAULT;
2327c478bd9Sstevel@tonic-gate eprintsoline(so, *errorp);
2337c478bd9Sstevel@tonic-gate return (NULL);
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate /*
2377c478bd9Sstevel@tonic-gate * Add space for NULL termination if needed.
2387c478bd9Sstevel@tonic-gate * Do a quick check if the last byte is NUL.
2397c478bd9Sstevel@tonic-gate */
2407c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX && faddr[namelen - 1] != '\0') {
2417c478bd9Sstevel@tonic-gate /* Check if there is any NULL termination */
2427c478bd9Sstevel@tonic-gate size_t i;
2437c478bd9Sstevel@tonic-gate int foundnull = 0;
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate for (i = sizeof (name->sa_family); i < namelen; i++) {
2467c478bd9Sstevel@tonic-gate if (faddr[i] == '\0') {
2477c478bd9Sstevel@tonic-gate foundnull = 1;
2487c478bd9Sstevel@tonic-gate break;
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate if (!foundnull) {
2527c478bd9Sstevel@tonic-gate /* Add extra byte for NUL padding */
2537c478bd9Sstevel@tonic-gate char *nfaddr;
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate nfaddr = (char *)kmem_alloc(namelen + 1, KM_SLEEP);
2567c478bd9Sstevel@tonic-gate bcopy(faddr, nfaddr, namelen);
2577c478bd9Sstevel@tonic-gate kmem_free(faddr, namelen);
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate /* NUL terminate */
2607c478bd9Sstevel@tonic-gate nfaddr[namelen] = '\0';
2617c478bd9Sstevel@tonic-gate namelen++;
2627c478bd9Sstevel@tonic-gate ASSERT((socklen_t)namelen == namelen);
2637c478bd9Sstevel@tonic-gate *namelenp = (socklen_t)namelen;
2647c478bd9Sstevel@tonic-gate faddr = nfaddr;
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate return ((struct sockaddr *)faddr);
2687c478bd9Sstevel@tonic-gate }
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate /*
2717c478bd9Sstevel@tonic-gate * Copy from kaddr/klen to uaddr/ulen. Updates ulenp if non-NULL.
2727c478bd9Sstevel@tonic-gate */
2737c478bd9Sstevel@tonic-gate static int
copyout_arg(void * uaddr,socklen_t ulen,void * ulenp,void * kaddr,socklen_t klen)2748cd31312SMarcel Telka copyout_arg(void *uaddr, socklen_t ulen, void *ulenp, void *kaddr,
2758cd31312SMarcel Telka socklen_t klen)
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate if (uaddr != NULL) {
2787c478bd9Sstevel@tonic-gate if (ulen > klen)
2797c478bd9Sstevel@tonic-gate ulen = klen;
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate if (ulen != 0) {
2827c478bd9Sstevel@tonic-gate if (copyout(kaddr, uaddr, ulen))
2837c478bd9Sstevel@tonic-gate return (EFAULT);
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate } else
2867c478bd9Sstevel@tonic-gate ulen = 0;
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate if (ulenp != NULL) {
2897c478bd9Sstevel@tonic-gate if (copyout(&ulen, ulenp, sizeof (ulen)))
2907c478bd9Sstevel@tonic-gate return (EFAULT);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate return (0);
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate /*
2967c478bd9Sstevel@tonic-gate * Copy from kaddr/klen to uaddr/ulen. Updates ulenp if non-NULL.
2977c478bd9Sstevel@tonic-gate * If klen is greater than ulen it still uses the non-truncated
2987c478bd9Sstevel@tonic-gate * klen to update ulenp.
2997c478bd9Sstevel@tonic-gate */
3007c478bd9Sstevel@tonic-gate static int
copyout_name(void * uaddr,socklen_t ulen,void * ulenp,void * kaddr,socklen_t klen)3018cd31312SMarcel Telka copyout_name(void *uaddr, socklen_t ulen, void *ulenp, void *kaddr,
3028cd31312SMarcel Telka socklen_t klen)
3037c478bd9Sstevel@tonic-gate {
3047c478bd9Sstevel@tonic-gate if (uaddr != NULL) {
3057c478bd9Sstevel@tonic-gate if (ulen >= klen)
3067c478bd9Sstevel@tonic-gate ulen = klen;
3077c478bd9Sstevel@tonic-gate else if (ulen != 0 && xnet_truncate_print) {
3087c478bd9Sstevel@tonic-gate printf("sockfs: truncating copyout of address using "
3097c478bd9Sstevel@tonic-gate "XNET semantics for pid = %d. Lengths %d, %d\n",
3107c478bd9Sstevel@tonic-gate curproc->p_pid, klen, ulen);
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate if (ulen != 0) {
3147c478bd9Sstevel@tonic-gate if (copyout(kaddr, uaddr, ulen))
3157c478bd9Sstevel@tonic-gate return (EFAULT);
3167c478bd9Sstevel@tonic-gate } else
3177c478bd9Sstevel@tonic-gate klen = 0;
3187c478bd9Sstevel@tonic-gate } else
3197c478bd9Sstevel@tonic-gate klen = 0;
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate if (ulenp != NULL) {
3227c478bd9Sstevel@tonic-gate if (copyout(&klen, ulenp, sizeof (klen)))
3237c478bd9Sstevel@tonic-gate return (EFAULT);
3247c478bd9Sstevel@tonic-gate }
3257c478bd9Sstevel@tonic-gate return (0);
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate /*
3297c478bd9Sstevel@tonic-gate * The socketpair() code in libsocket creates two sockets (using
3307c478bd9Sstevel@tonic-gate * the /etc/netconfig fallback if needed) before calling this routine
3317c478bd9Sstevel@tonic-gate * to connect the two sockets together.
3327c478bd9Sstevel@tonic-gate *
3337c478bd9Sstevel@tonic-gate * For a SOCK_STREAM socketpair a listener is needed - in that case this
3347c478bd9Sstevel@tonic-gate * routine will create a new file descriptor as part of accepting the
3357c478bd9Sstevel@tonic-gate * connection. The library socketpair() will check if svs[2] has changed
3367c478bd9Sstevel@tonic-gate * in which case it will close the changed fd.
3377c478bd9Sstevel@tonic-gate *
3387c478bd9Sstevel@tonic-gate * Note that this code could use the TPI feature of accepting the connection
3397c478bd9Sstevel@tonic-gate * on the listening endpoint. However, that would require significant changes
3407c478bd9Sstevel@tonic-gate * to soaccept.
3417c478bd9Sstevel@tonic-gate */
3427c478bd9Sstevel@tonic-gate int
so_socketpair(int sv[2])3437c478bd9Sstevel@tonic-gate so_socketpair(int sv[2])
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate int svs[2];
3467c478bd9Sstevel@tonic-gate struct sonode *so1, *so2;
3477c478bd9Sstevel@tonic-gate int error;
3485dbfd19aSTheo Schlossnagle int orig_flags;
3497c478bd9Sstevel@tonic-gate struct sockaddr_ux *name;
3507c478bd9Sstevel@tonic-gate size_t namelen;
3510f1702c5SYu Xiangning sotpi_info_t *sti1;
3520f1702c5SYu Xiangning sotpi_info_t *sti2;
3537c478bd9Sstevel@tonic-gate
354903a11ebSrh dprint(1, ("so_socketpair(%p)\n", (void *)sv));
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate error = useracc(sv, sizeof (svs), B_WRITE);
3577c478bd9Sstevel@tonic-gate if (error && do_useracc)
3587c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate if (copyin(sv, svs, sizeof (svs)))
3617c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate if ((so1 = getsonode(svs[0], &error, NULL)) == NULL)
3647c478bd9Sstevel@tonic-gate return (set_errno(error));
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate if ((so2 = getsonode(svs[1], &error, NULL)) == NULL) {
3677c478bd9Sstevel@tonic-gate releasef(svs[0]);
3687c478bd9Sstevel@tonic-gate return (set_errno(error));
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate if (so1->so_family != AF_UNIX || so2->so_family != AF_UNIX) {
3727c478bd9Sstevel@tonic-gate error = EOPNOTSUPP;
3737c478bd9Sstevel@tonic-gate goto done;
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate
3760f1702c5SYu Xiangning sti1 = SOTOTPI(so1);
3770f1702c5SYu Xiangning sti2 = SOTOTPI(so2);
3780f1702c5SYu Xiangning
3797c478bd9Sstevel@tonic-gate /*
3807c478bd9Sstevel@tonic-gate * The code below makes assumptions about the "sockfs" implementation.
3817c478bd9Sstevel@tonic-gate * So make sure that the correct implementation is really used.
3827c478bd9Sstevel@tonic-gate */
3837c478bd9Sstevel@tonic-gate ASSERT(so1->so_ops == &sotpi_sonodeops);
3847c478bd9Sstevel@tonic-gate ASSERT(so2->so_ops == &sotpi_sonodeops);
3857c478bd9Sstevel@tonic-gate
3867c478bd9Sstevel@tonic-gate if (so1->so_type == SOCK_DGRAM) {
3877c478bd9Sstevel@tonic-gate /*
3887c478bd9Sstevel@tonic-gate * Bind both sockets and connect them with each other.
3897c478bd9Sstevel@tonic-gate * Need to allocate name/namelen for soconnect.
3907c478bd9Sstevel@tonic-gate */
3910f1702c5SYu Xiangning error = socket_bind(so1, NULL, 0, _SOBIND_UNSPEC, CRED());
3927c478bd9Sstevel@tonic-gate if (error) {
3937c478bd9Sstevel@tonic-gate eprintsoline(so1, error);
3947c478bd9Sstevel@tonic-gate goto done;
3957c478bd9Sstevel@tonic-gate }
3960f1702c5SYu Xiangning error = socket_bind(so2, NULL, 0, _SOBIND_UNSPEC, CRED());
3977c478bd9Sstevel@tonic-gate if (error) {
3987c478bd9Sstevel@tonic-gate eprintsoline(so2, error);
3997c478bd9Sstevel@tonic-gate goto done;
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate namelen = sizeof (struct sockaddr_ux);
4027c478bd9Sstevel@tonic-gate name = kmem_alloc(namelen, KM_SLEEP);
4037c478bd9Sstevel@tonic-gate name->sou_family = AF_UNIX;
4040f1702c5SYu Xiangning name->sou_addr = sti2->sti_ux_laddr;
4050f1702c5SYu Xiangning error = socket_connect(so1,
406745b2690Stz (struct sockaddr *)name,
407745b2690Stz (socklen_t)namelen,
4080f1702c5SYu Xiangning 0, _SOCONNECT_NOXLATE, CRED());
4097c478bd9Sstevel@tonic-gate if (error) {
4107c478bd9Sstevel@tonic-gate kmem_free(name, namelen);
4117c478bd9Sstevel@tonic-gate eprintsoline(so1, error);
4127c478bd9Sstevel@tonic-gate goto done;
4137c478bd9Sstevel@tonic-gate }
4140f1702c5SYu Xiangning name->sou_addr = sti1->sti_ux_laddr;
4150f1702c5SYu Xiangning error = socket_connect(so2,
416745b2690Stz (struct sockaddr *)name,
417745b2690Stz (socklen_t)namelen,
4180f1702c5SYu Xiangning 0, _SOCONNECT_NOXLATE, CRED());
4197c478bd9Sstevel@tonic-gate kmem_free(name, namelen);
4207c478bd9Sstevel@tonic-gate if (error) {
4217c478bd9Sstevel@tonic-gate eprintsoline(so2, error);
4227c478bd9Sstevel@tonic-gate goto done;
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate releasef(svs[0]);
4257c478bd9Sstevel@tonic-gate releasef(svs[1]);
4267c478bd9Sstevel@tonic-gate } else {
4277c478bd9Sstevel@tonic-gate /*
4287c478bd9Sstevel@tonic-gate * Bind both sockets, with so1 being a listener.
4297c478bd9Sstevel@tonic-gate * Connect so2 to so1 - nonblocking to avoid waiting for
4307c478bd9Sstevel@tonic-gate * soaccept to complete.
4317c478bd9Sstevel@tonic-gate * Accept a connection on so1. Pass out the new fd as sv[0].
4327c478bd9Sstevel@tonic-gate * The library will detect the changed fd and close
4337c478bd9Sstevel@tonic-gate * the original one.
4347c478bd9Sstevel@tonic-gate */
4357c478bd9Sstevel@tonic-gate struct sonode *nso;
4367c478bd9Sstevel@tonic-gate struct vnode *nvp;
4377c478bd9Sstevel@tonic-gate struct file *nfp;
4387c478bd9Sstevel@tonic-gate int nfd;
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate /*
4410f1702c5SYu Xiangning * We could simply call socket_listen() here (which would do the
4427c478bd9Sstevel@tonic-gate * binding automatically) if the code didn't rely on passing
4430f1702c5SYu Xiangning * _SOBIND_NOXLATE to the TPI implementation of socket_bind().
4447c478bd9Sstevel@tonic-gate */
4450f1702c5SYu Xiangning error = socket_bind(so1, NULL, 0, _SOBIND_UNSPEC|
4460f1702c5SYu Xiangning _SOBIND_NOXLATE|_SOBIND_LISTEN|_SOBIND_SOCKETPAIR,
4470f1702c5SYu Xiangning CRED());
4487c478bd9Sstevel@tonic-gate if (error) {
4497c478bd9Sstevel@tonic-gate eprintsoline(so1, error);
4507c478bd9Sstevel@tonic-gate goto done;
4517c478bd9Sstevel@tonic-gate }
4520f1702c5SYu Xiangning error = socket_bind(so2, NULL, 0, _SOBIND_UNSPEC, CRED());
4537c478bd9Sstevel@tonic-gate if (error) {
4547c478bd9Sstevel@tonic-gate eprintsoline(so2, error);
4557c478bd9Sstevel@tonic-gate goto done;
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate namelen = sizeof (struct sockaddr_ux);
4597c478bd9Sstevel@tonic-gate name = kmem_alloc(namelen, KM_SLEEP);
4607c478bd9Sstevel@tonic-gate name->sou_family = AF_UNIX;
4610f1702c5SYu Xiangning name->sou_addr = sti1->sti_ux_laddr;
4620f1702c5SYu Xiangning error = socket_connect(so2,
463745b2690Stz (struct sockaddr *)name,
464745b2690Stz (socklen_t)namelen,
4650f1702c5SYu Xiangning FNONBLOCK, _SOCONNECT_NOXLATE, CRED());
4667c478bd9Sstevel@tonic-gate kmem_free(name, namelen);
4677c478bd9Sstevel@tonic-gate if (error) {
4687c478bd9Sstevel@tonic-gate if (error != EINPROGRESS) {
4690f1702c5SYu Xiangning eprintsoline(so2, error); goto done;
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate
4730f1702c5SYu Xiangning error = socket_accept(so1, 0, CRED(), &nso);
4747c478bd9Sstevel@tonic-gate if (error) {
4757c478bd9Sstevel@tonic-gate eprintsoline(so1, error);
4767c478bd9Sstevel@tonic-gate goto done;
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate /* wait for so2 being SS_CONNECTED ignoring signals */
4807c478bd9Sstevel@tonic-gate mutex_enter(&so2->so_lock);
4817c478bd9Sstevel@tonic-gate error = sowaitconnected(so2, 0, 1);
4827c478bd9Sstevel@tonic-gate mutex_exit(&so2->so_lock);
4837c478bd9Sstevel@tonic-gate if (error != 0) {
4840f1702c5SYu Xiangning (void) socket_close(nso, 0, CRED());
4850f1702c5SYu Xiangning socket_destroy(nso);
4867c478bd9Sstevel@tonic-gate eprintsoline(so2, error);
4877c478bd9Sstevel@tonic-gate goto done;
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate
4900f1702c5SYu Xiangning nvp = SOTOV(nso);
491*34793d0fSToomas Soome error = falloc(nvp, FWRITE|FREAD, &nfp, &nfd);
492*34793d0fSToomas Soome if (error != 0) {
4930f1702c5SYu Xiangning (void) socket_close(nso, 0, CRED());
4940f1702c5SYu Xiangning socket_destroy(nso);
4957c478bd9Sstevel@tonic-gate eprintsoline(nso, error);
4967c478bd9Sstevel@tonic-gate goto done;
4977c478bd9Sstevel@tonic-gate }
498a63a4ea3SKeith M Wesolowski /*
499a63a4ea3SKeith M Wesolowski * copy over FNONBLOCK and FNDELAY flags should they exist
500a63a4ea3SKeith M Wesolowski */
501a63a4ea3SKeith M Wesolowski if (so1->so_state & SS_NONBLOCK)
502a63a4ea3SKeith M Wesolowski nfp->f_flag |= FNONBLOCK;
503a63a4ea3SKeith M Wesolowski if (so1->so_state & SS_NDELAY)
504a63a4ea3SKeith M Wesolowski nfp->f_flag |= FNDELAY;
505a63a4ea3SKeith M Wesolowski
5067c478bd9Sstevel@tonic-gate /*
5077c478bd9Sstevel@tonic-gate * fill in the entries that falloc reserved
5087c478bd9Sstevel@tonic-gate */
5097c478bd9Sstevel@tonic-gate mutex_exit(&nfp->f_tlock);
5107c478bd9Sstevel@tonic-gate setf(nfd, nfp);
5117c478bd9Sstevel@tonic-gate
512a63a4ea3SKeith M Wesolowski /*
513a63a4ea3SKeith M Wesolowski * get the original flags before we release
514a63a4ea3SKeith M Wesolowski */
515a63a4ea3SKeith M Wesolowski VERIFY(f_getfd_error(svs[0], &orig_flags) == 0);
516a63a4ea3SKeith M Wesolowski
5177c478bd9Sstevel@tonic-gate releasef(svs[0]);
5187c478bd9Sstevel@tonic-gate releasef(svs[1]);
5195dbfd19aSTheo Schlossnagle
5205dbfd19aSTheo Schlossnagle /*
5215dbfd19aSTheo Schlossnagle * If FD_CLOEXEC was set on the filedescriptor we're
5225dbfd19aSTheo Schlossnagle * swapping out, we should set it on the new one too.
5235dbfd19aSTheo Schlossnagle */
5245dbfd19aSTheo Schlossnagle if (orig_flags & FD_CLOEXEC) {
5255dbfd19aSTheo Schlossnagle f_setfd(nfd, FD_CLOEXEC);
5265dbfd19aSTheo Schlossnagle }
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate /*
5297c478bd9Sstevel@tonic-gate * The socketpair library routine will close the original
5307c478bd9Sstevel@tonic-gate * svs[0] when this code passes out a different file
5317c478bd9Sstevel@tonic-gate * descriptor.
5327c478bd9Sstevel@tonic-gate */
5335dbfd19aSTheo Schlossnagle svs[0] = nfd;
5345dbfd19aSTheo Schlossnagle
5357c478bd9Sstevel@tonic-gate if (copyout(svs, sv, sizeof (svs))) {
5367c478bd9Sstevel@tonic-gate (void) closeandsetf(nfd, NULL);
5377c478bd9Sstevel@tonic-gate eprintline(EFAULT);
5387c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
5397c478bd9Sstevel@tonic-gate }
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate return (0);
5427c478bd9Sstevel@tonic-gate
5437c478bd9Sstevel@tonic-gate done:
5447c478bd9Sstevel@tonic-gate releasef(svs[0]);
5457c478bd9Sstevel@tonic-gate releasef(svs[1]);
5467c478bd9Sstevel@tonic-gate return (set_errno(error));
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate int
bind(int sock,struct sockaddr * name,socklen_t namelen,int version)5507c478bd9Sstevel@tonic-gate bind(int sock, struct sockaddr *name, socklen_t namelen, int version)
5517c478bd9Sstevel@tonic-gate {
5527c478bd9Sstevel@tonic-gate struct sonode *so;
5537c478bd9Sstevel@tonic-gate int error;
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate dprint(1, ("bind(%d, %p, %d)\n",
556903a11ebSrh sock, (void *)name, namelen));
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
5597c478bd9Sstevel@tonic-gate return (set_errno(error));
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate /* Allocate and copyin name */
5627c478bd9Sstevel@tonic-gate /*
5637c478bd9Sstevel@tonic-gate * X/Open test does not expect EFAULT with NULL name and non-zero
5647c478bd9Sstevel@tonic-gate * namelen.
5657c478bd9Sstevel@tonic-gate */
5667c478bd9Sstevel@tonic-gate if (name != NULL && namelen != 0) {
5677c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
5687c478bd9Sstevel@tonic-gate name = copyin_name(so, name, &namelen, &error);
5697c478bd9Sstevel@tonic-gate if (name == NULL) {
5707c478bd9Sstevel@tonic-gate releasef(sock);
5717c478bd9Sstevel@tonic-gate return (set_errno(error));
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate } else {
5747c478bd9Sstevel@tonic-gate name = NULL;
5757c478bd9Sstevel@tonic-gate namelen = 0;
5767c478bd9Sstevel@tonic-gate }
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate switch (version) {
5797c478bd9Sstevel@tonic-gate default:
5800f1702c5SYu Xiangning error = socket_bind(so, name, namelen, 0, CRED());
5817c478bd9Sstevel@tonic-gate break;
5827c478bd9Sstevel@tonic-gate case SOV_XPG4_2:
5830f1702c5SYu Xiangning error = socket_bind(so, name, namelen, _SOBIND_XPG4_2, CRED());
5847c478bd9Sstevel@tonic-gate break;
5857c478bd9Sstevel@tonic-gate case SOV_SOCKBSD:
5860f1702c5SYu Xiangning error = socket_bind(so, name, namelen, _SOBIND_SOCKBSD, CRED());
5877c478bd9Sstevel@tonic-gate break;
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate done:
5907c478bd9Sstevel@tonic-gate releasef(sock);
5917c478bd9Sstevel@tonic-gate if (name != NULL)
5927c478bd9Sstevel@tonic-gate kmem_free(name, (size_t)namelen);
5937c478bd9Sstevel@tonic-gate
5947c478bd9Sstevel@tonic-gate if (error)
5957c478bd9Sstevel@tonic-gate return (set_errno(error));
5967c478bd9Sstevel@tonic-gate return (0);
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
6007c478bd9Sstevel@tonic-gate int
listen(int sock,int backlog,int version)6017c478bd9Sstevel@tonic-gate listen(int sock, int backlog, int version)
6027c478bd9Sstevel@tonic-gate {
6037c478bd9Sstevel@tonic-gate struct sonode *so;
6047c478bd9Sstevel@tonic-gate int error;
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate dprint(1, ("listen(%d, %d)\n",
607745b2690Stz sock, backlog));
6087c478bd9Sstevel@tonic-gate
6097c478bd9Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
6107c478bd9Sstevel@tonic-gate return (set_errno(error));
6117c478bd9Sstevel@tonic-gate
6120f1702c5SYu Xiangning error = socket_listen(so, backlog, CRED());
6137c478bd9Sstevel@tonic-gate
6147c478bd9Sstevel@tonic-gate releasef(sock);
6157c478bd9Sstevel@tonic-gate if (error)
6167c478bd9Sstevel@tonic-gate return (set_errno(error));
6177c478bd9Sstevel@tonic-gate return (0);
6187c478bd9Sstevel@tonic-gate }
6197c478bd9Sstevel@tonic-gate
6205eaceb49STheo Schlossnagle /*ARGSUSED3*/
6217c478bd9Sstevel@tonic-gate int
accept(int sock,struct sockaddr * name,socklen_t * namelenp,int version,int flags)6225dbfd19aSTheo Schlossnagle accept(int sock, struct sockaddr *name, socklen_t *namelenp, int version,
6235dbfd19aSTheo Schlossnagle int flags)
6247c478bd9Sstevel@tonic-gate {
6257c478bd9Sstevel@tonic-gate struct sonode *so;
6267c478bd9Sstevel@tonic-gate file_t *fp;
6277c478bd9Sstevel@tonic-gate int error;
6287c478bd9Sstevel@tonic-gate socklen_t namelen;
6297c478bd9Sstevel@tonic-gate struct sonode *nso;
6307c478bd9Sstevel@tonic-gate struct vnode *nvp;
6317c478bd9Sstevel@tonic-gate struct file *nfp;
6327c478bd9Sstevel@tonic-gate int nfd;
6335dbfd19aSTheo Schlossnagle int ssflags;
6340f1702c5SYu Xiangning struct sockaddr *addrp;
6350f1702c5SYu Xiangning socklen_t addrlen;
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate dprint(1, ("accept(%d, %p, %p)\n",
638903a11ebSrh sock, (void *)name, (void *)namelenp));
6397c478bd9Sstevel@tonic-gate
6405dbfd19aSTheo Schlossnagle if (flags & ~(SOCK_CLOEXEC|SOCK_NONBLOCK|SOCK_NDELAY)) {
6415dbfd19aSTheo Schlossnagle return (set_errno(EINVAL));
6425dbfd19aSTheo Schlossnagle }
6435dbfd19aSTheo Schlossnagle
6445dbfd19aSTheo Schlossnagle /* Translate SOCK_ flags to their SS_ variant */
6455dbfd19aSTheo Schlossnagle ssflags = 0;
6465dbfd19aSTheo Schlossnagle if (flags & SOCK_NONBLOCK)
6475dbfd19aSTheo Schlossnagle ssflags |= SS_NONBLOCK;
6485dbfd19aSTheo Schlossnagle if (flags & SOCK_NDELAY)
6495dbfd19aSTheo Schlossnagle ssflags |= SS_NDELAY;
6505dbfd19aSTheo Schlossnagle
6517c478bd9Sstevel@tonic-gate if ((so = getsonode(sock, &error, &fp)) == NULL)
6527c478bd9Sstevel@tonic-gate return (set_errno(error));
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate if (name != NULL) {
6557c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
6567c478bd9Sstevel@tonic-gate if (copyin(namelenp, &namelen, sizeof (namelen))) {
6577c478bd9Sstevel@tonic-gate releasef(sock);
6587c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate if (namelen != 0) {
6617c478bd9Sstevel@tonic-gate error = useracc(name, (size_t)namelen, B_WRITE);
6627c478bd9Sstevel@tonic-gate if (error && do_useracc) {
6637c478bd9Sstevel@tonic-gate releasef(sock);
6647c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate } else
6677c478bd9Sstevel@tonic-gate name = NULL;
6687c478bd9Sstevel@tonic-gate } else {
6697c478bd9Sstevel@tonic-gate namelen = 0;
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate /*
6730f1702c5SYu Xiangning * Allocate the user fd before socket_accept() in order to
6740f1702c5SYu Xiangning * catch EMFILE errors before calling socket_accept().
6757c478bd9Sstevel@tonic-gate */
6767c478bd9Sstevel@tonic-gate if ((nfd = ufalloc(0)) == -1) {
6777c478bd9Sstevel@tonic-gate eprintsoline(so, EMFILE);
6787c478bd9Sstevel@tonic-gate releasef(sock);
6797c478bd9Sstevel@tonic-gate return (set_errno(EMFILE));
6807c478bd9Sstevel@tonic-gate }
6810f1702c5SYu Xiangning error = socket_accept(so, fp->f_flag, CRED(), &nso);
6827c478bd9Sstevel@tonic-gate if (error) {
6837c478bd9Sstevel@tonic-gate setf(nfd, NULL);
6847f9e9054SJayakara Kini releasef(sock);
6857c478bd9Sstevel@tonic-gate return (set_errno(error));
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate nvp = SOTOV(nso);
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&nso->so_lock));
6910f1702c5SYu Xiangning if (namelen != 0) {
6920f1702c5SYu Xiangning addrlen = so->so_max_addr_len;
6930f1702c5SYu Xiangning addrp = (struct sockaddr *)kmem_alloc(addrlen, KM_SLEEP);
6940f1702c5SYu Xiangning
6950f1702c5SYu Xiangning if ((error = socket_getpeername(nso, (struct sockaddr *)addrp,
6960f1702c5SYu Xiangning &addrlen, B_TRUE, CRED())) == 0) {
6970f1702c5SYu Xiangning error = copyout_name(name, namelen, namelenp,
6980f1702c5SYu Xiangning addrp, addrlen);
6990f1702c5SYu Xiangning } else {
7000f1702c5SYu Xiangning ASSERT(error == EINVAL || error == ENOTCONN);
7010f1702c5SYu Xiangning error = ECONNABORTED;
7020f1702c5SYu Xiangning }
7030f1702c5SYu Xiangning kmem_free(addrp, so->so_max_addr_len);
7040f1702c5SYu Xiangning }
7050f1702c5SYu Xiangning
7067c478bd9Sstevel@tonic-gate if (error) {
7077c478bd9Sstevel@tonic-gate setf(nfd, NULL);
7080f1702c5SYu Xiangning (void) socket_close(nso, 0, CRED());
7090f1702c5SYu Xiangning socket_destroy(nso);
7107f9e9054SJayakara Kini releasef(sock);
7117c478bd9Sstevel@tonic-gate return (set_errno(error));
7127c478bd9Sstevel@tonic-gate }
713*34793d0fSToomas Soome error = falloc(NULL, FWRITE|FREAD, &nfp, NULL);
714*34793d0fSToomas Soome if (error != 0) {
7157c478bd9Sstevel@tonic-gate setf(nfd, NULL);
7160f1702c5SYu Xiangning (void) socket_close(nso, 0, CRED());
7170f1702c5SYu Xiangning socket_destroy(nso);
7187c478bd9Sstevel@tonic-gate eprintsoline(so, error);
7197f9e9054SJayakara Kini releasef(sock);
7207c478bd9Sstevel@tonic-gate return (set_errno(error));
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate /*
7237c478bd9Sstevel@tonic-gate * fill in the entries that falloc reserved
7247c478bd9Sstevel@tonic-gate */
7257c478bd9Sstevel@tonic-gate nfp->f_vnode = nvp;
7267c478bd9Sstevel@tonic-gate mutex_exit(&nfp->f_tlock);
7277c478bd9Sstevel@tonic-gate setf(nfd, nfp);
7287c478bd9Sstevel@tonic-gate
7295dbfd19aSTheo Schlossnagle /*
7305dbfd19aSTheo Schlossnagle * Act on SOCK_CLOEXEC from flags
7315dbfd19aSTheo Schlossnagle */
7325dbfd19aSTheo Schlossnagle if (flags & SOCK_CLOEXEC) {
7335dbfd19aSTheo Schlossnagle f_setfd(nfd, FD_CLOEXEC);
7345dbfd19aSTheo Schlossnagle }
7355dbfd19aSTheo Schlossnagle
7367c478bd9Sstevel@tonic-gate /*
7377c478bd9Sstevel@tonic-gate * Copy FNDELAY and FNONBLOCK from listener to acceptor
7385dbfd19aSTheo Schlossnagle * and from ssflags
7397c478bd9Sstevel@tonic-gate */
7405dbfd19aSTheo Schlossnagle if ((ssflags | so->so_state) & (SS_NDELAY|SS_NONBLOCK)) {
7417c478bd9Sstevel@tonic-gate uint_t oflag = nfp->f_flag;
7427c478bd9Sstevel@tonic-gate int arg = 0;
7437c478bd9Sstevel@tonic-gate
7445dbfd19aSTheo Schlossnagle if ((ssflags | so->so_state) & SS_NONBLOCK)
7457c478bd9Sstevel@tonic-gate arg |= FNONBLOCK;
7465dbfd19aSTheo Schlossnagle else if ((ssflags | so->so_state) & SS_NDELAY)
7477c478bd9Sstevel@tonic-gate arg |= FNDELAY;
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate /*
7507c478bd9Sstevel@tonic-gate * This code is a simplification of the F_SETFL code in fcntl()
7517c478bd9Sstevel@tonic-gate * Ignore any errors from VOP_SETFL.
7527c478bd9Sstevel@tonic-gate */
753da6c28aaSamw if ((error = VOP_SETFL(nvp, oflag, arg, nfp->f_cred, NULL))
754da6c28aaSamw != 0) {
7557c478bd9Sstevel@tonic-gate eprintsoline(so, error);
7567c478bd9Sstevel@tonic-gate error = 0;
7577c478bd9Sstevel@tonic-gate } else {
7587c478bd9Sstevel@tonic-gate mutex_enter(&nfp->f_tlock);
7597c478bd9Sstevel@tonic-gate nfp->f_flag &= ~FMASK | (FREAD|FWRITE);
7607c478bd9Sstevel@tonic-gate nfp->f_flag |= arg;
7617c478bd9Sstevel@tonic-gate mutex_exit(&nfp->f_tlock);
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate }
7647f9e9054SJayakara Kini releasef(sock);
7657c478bd9Sstevel@tonic-gate return (nfd);
7667c478bd9Sstevel@tonic-gate }
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate int
connect(int sock,struct sockaddr * name,socklen_t namelen,int version)7697c478bd9Sstevel@tonic-gate connect(int sock, struct sockaddr *name, socklen_t namelen, int version)
7707c478bd9Sstevel@tonic-gate {
7717c478bd9Sstevel@tonic-gate struct sonode *so;
7727c478bd9Sstevel@tonic-gate file_t *fp;
7737c478bd9Sstevel@tonic-gate int error;
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate dprint(1, ("connect(%d, %p, %d)\n",
776903a11ebSrh sock, (void *)name, namelen));
7777c478bd9Sstevel@tonic-gate
7787c478bd9Sstevel@tonic-gate if ((so = getsonode(sock, &error, &fp)) == NULL)
7797c478bd9Sstevel@tonic-gate return (set_errno(error));
7807c478bd9Sstevel@tonic-gate
7817c478bd9Sstevel@tonic-gate /* Allocate and copyin name */
7827c478bd9Sstevel@tonic-gate if (namelen != 0) {
7837c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
7847c478bd9Sstevel@tonic-gate name = copyin_name(so, name, &namelen, &error);
7857c478bd9Sstevel@tonic-gate if (name == NULL) {
7867c478bd9Sstevel@tonic-gate releasef(sock);
7877c478bd9Sstevel@tonic-gate return (set_errno(error));
7887c478bd9Sstevel@tonic-gate }
7897c478bd9Sstevel@tonic-gate } else
7907c478bd9Sstevel@tonic-gate name = NULL;
7917c478bd9Sstevel@tonic-gate
7920f1702c5SYu Xiangning error = socket_connect(so, name, namelen, fp->f_flag,
7930f1702c5SYu Xiangning (version != SOV_XPG4_2) ? 0 : _SOCONNECT_XPG4_2, CRED());
7947c478bd9Sstevel@tonic-gate releasef(sock);
7957c478bd9Sstevel@tonic-gate if (name)
7967c478bd9Sstevel@tonic-gate kmem_free(name, (size_t)namelen);
7977c478bd9Sstevel@tonic-gate if (error)
7987c478bd9Sstevel@tonic-gate return (set_errno(error));
7997c478bd9Sstevel@tonic-gate return (0);
8007c478bd9Sstevel@tonic-gate }
8017c478bd9Sstevel@tonic-gate
8027c478bd9Sstevel@tonic-gate /*ARGSUSED2*/
8037c478bd9Sstevel@tonic-gate int
shutdown(int sock,int how,int version)8047c478bd9Sstevel@tonic-gate shutdown(int sock, int how, int version)
8057c478bd9Sstevel@tonic-gate {
8067c478bd9Sstevel@tonic-gate struct sonode *so;
8077c478bd9Sstevel@tonic-gate int error;
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate dprint(1, ("shutdown(%d, %d)\n",
810745b2690Stz sock, how));
8117c478bd9Sstevel@tonic-gate
8127c478bd9Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
8137c478bd9Sstevel@tonic-gate return (set_errno(error));
8147c478bd9Sstevel@tonic-gate
8150f1702c5SYu Xiangning error = socket_shutdown(so, how, CRED());
8167c478bd9Sstevel@tonic-gate
8177c478bd9Sstevel@tonic-gate releasef(sock);
8187c478bd9Sstevel@tonic-gate if (error)
8197c478bd9Sstevel@tonic-gate return (set_errno(error));
8207c478bd9Sstevel@tonic-gate return (0);
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate /*
8247c478bd9Sstevel@tonic-gate * Common receive routine.
8257c478bd9Sstevel@tonic-gate */
8267c478bd9Sstevel@tonic-gate static ssize_t
recvit(int sock,struct nmsghdr * msg,struct uio * uiop,int flags,socklen_t * namelenp,socklen_t * controllenp,int * flagsp)8278cd31312SMarcel Telka recvit(int sock, struct nmsghdr *msg, struct uio *uiop, int flags,
8288cd31312SMarcel Telka socklen_t *namelenp, socklen_t *controllenp, int *flagsp)
8297c478bd9Sstevel@tonic-gate {
8307c478bd9Sstevel@tonic-gate struct sonode *so;
8317c478bd9Sstevel@tonic-gate file_t *fp;
8327c478bd9Sstevel@tonic-gate void *name;
8337c478bd9Sstevel@tonic-gate socklen_t namelen;
8347c478bd9Sstevel@tonic-gate void *control;
835d865fc92SAndy Fiddaman socklen_t controllen, free_controllen;
8367c478bd9Sstevel@tonic-gate ssize_t len;
8377c478bd9Sstevel@tonic-gate int error;
8387c478bd9Sstevel@tonic-gate
8397c478bd9Sstevel@tonic-gate if ((so = getsonode(sock, &error, &fp)) == NULL)
8407c478bd9Sstevel@tonic-gate return (set_errno(error));
8417c478bd9Sstevel@tonic-gate
8427c478bd9Sstevel@tonic-gate len = uiop->uio_resid;
8437c478bd9Sstevel@tonic-gate uiop->uio_fmode = fp->f_flag;
8447c478bd9Sstevel@tonic-gate uiop->uio_extflg = UIO_COPY_CACHED;
8457c478bd9Sstevel@tonic-gate
8467c478bd9Sstevel@tonic-gate name = msg->msg_name;
8477c478bd9Sstevel@tonic-gate namelen = msg->msg_namelen;
8487c478bd9Sstevel@tonic-gate control = msg->msg_control;
8497c478bd9Sstevel@tonic-gate controllen = msg->msg_controllen;
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate msg->msg_flags = flags & (MSG_OOB | MSG_PEEK | MSG_WAITALL |
8527c478bd9Sstevel@tonic-gate MSG_DONTWAIT | MSG_XPG4_2);
8537c478bd9Sstevel@tonic-gate
8540f1702c5SYu Xiangning error = socket_recvmsg(so, msg, uiop, CRED());
8557c478bd9Sstevel@tonic-gate if (error) {
8567c478bd9Sstevel@tonic-gate releasef(sock);
8577c478bd9Sstevel@tonic-gate return (set_errno(error));
8587c478bd9Sstevel@tonic-gate }
8597c478bd9Sstevel@tonic-gate lwp_stat_update(LWP_STAT_MSGRCV, 1);
8607c478bd9Sstevel@tonic-gate releasef(sock);
8617c478bd9Sstevel@tonic-gate
862d865fc92SAndy Fiddaman free_controllen = msg->msg_controllen;
863d865fc92SAndy Fiddaman
8647c478bd9Sstevel@tonic-gate error = copyout_name(name, namelen, namelenp,
8657c478bd9Sstevel@tonic-gate msg->msg_name, msg->msg_namelen);
8667c478bd9Sstevel@tonic-gate if (error)
8677c478bd9Sstevel@tonic-gate goto err;
8687c478bd9Sstevel@tonic-gate
8697c478bd9Sstevel@tonic-gate if (flagsp != NULL) {
8707c478bd9Sstevel@tonic-gate /*
8717c478bd9Sstevel@tonic-gate * Clear internal flag.
8727c478bd9Sstevel@tonic-gate */
8737c478bd9Sstevel@tonic-gate msg->msg_flags &= ~MSG_XPG4_2;
8747c478bd9Sstevel@tonic-gate
8757c478bd9Sstevel@tonic-gate /*
8767c478bd9Sstevel@tonic-gate * Determine MSG_CTRUNC. sorecvmsg sets MSG_CTRUNC only
8777c478bd9Sstevel@tonic-gate * when controllen is zero and there is control data to
8787c478bd9Sstevel@tonic-gate * copy out.
8797c478bd9Sstevel@tonic-gate */
8807c478bd9Sstevel@tonic-gate if (controllen != 0 &&
8817c478bd9Sstevel@tonic-gate (msg->msg_controllen > controllen || control == NULL)) {
8827c478bd9Sstevel@tonic-gate dprint(1, ("recvit: CTRUNC %d %d %p\n",
8837c478bd9Sstevel@tonic-gate msg->msg_controllen, controllen, control));
8847c478bd9Sstevel@tonic-gate
8857c478bd9Sstevel@tonic-gate msg->msg_flags |= MSG_CTRUNC;
8867c478bd9Sstevel@tonic-gate }
8877c478bd9Sstevel@tonic-gate if (copyout(&msg->msg_flags, flagsp,
8887c478bd9Sstevel@tonic-gate sizeof (msg->msg_flags))) {
8897c478bd9Sstevel@tonic-gate error = EFAULT;
8907c478bd9Sstevel@tonic-gate goto err;
8917c478bd9Sstevel@tonic-gate }
8927c478bd9Sstevel@tonic-gate }
893d865fc92SAndy Fiddaman
8947c478bd9Sstevel@tonic-gate if (controllen != 0) {
8957c478bd9Sstevel@tonic-gate if (!(flags & MSG_XPG4_2)) {
8967c478bd9Sstevel@tonic-gate /*
8977c478bd9Sstevel@tonic-gate * Good old msg_accrights can only return a multiple
8987c478bd9Sstevel@tonic-gate * of 4 bytes.
8997c478bd9Sstevel@tonic-gate */
9007c478bd9Sstevel@tonic-gate controllen &= ~((int)sizeof (uint32_t) - 1);
9017c478bd9Sstevel@tonic-gate }
902d865fc92SAndy Fiddaman
903d865fc92SAndy Fiddaman if (msg->msg_controllen > controllen || control == NULL) {
904d865fc92SAndy Fiddaman /*
905d865fc92SAndy Fiddaman * If the truncated part contains file descriptors,
906d865fc92SAndy Fiddaman * then they must be closed in the kernel as they
907d865fc92SAndy Fiddaman * will not be included in the data returned to
908d865fc92SAndy Fiddaman * user space. Close them now so that the header size
909d865fc92SAndy Fiddaman * can be safely adjusted prior to copyout. In case of
910d865fc92SAndy Fiddaman * an error during copyout, the remaining file
911d865fc92SAndy Fiddaman * descriptors will be closed in the error handler
912d865fc92SAndy Fiddaman * below.
913d865fc92SAndy Fiddaman */
914d865fc92SAndy Fiddaman so_closefds(msg->msg_control, msg->msg_controllen,
915d865fc92SAndy Fiddaman !(flags & MSG_XPG4_2),
916d865fc92SAndy Fiddaman control == NULL ? 0 : controllen);
917d865fc92SAndy Fiddaman
918d865fc92SAndy Fiddaman /*
919d865fc92SAndy Fiddaman * In the case of a truncated control message, the last
920d865fc92SAndy Fiddaman * cmsg header that fits into the available buffer
921d865fc92SAndy Fiddaman * space must be adjusted to reflect the actual amount
922d865fc92SAndy Fiddaman * of associated data that will be returned. This only
923d865fc92SAndy Fiddaman * needs to be done for XPG4 messages as non-XPG4
924d865fc92SAndy Fiddaman * messages are not structured (they are just a
925d865fc92SAndy Fiddaman * buffer and a length - msg_accrights(len)).
926d865fc92SAndy Fiddaman */
927d865fc92SAndy Fiddaman if (control != NULL && (flags & MSG_XPG4_2)) {
928d865fc92SAndy Fiddaman so_truncatecmsg(msg->msg_control,
929d865fc92SAndy Fiddaman msg->msg_controllen, controllen);
930d865fc92SAndy Fiddaman msg->msg_controllen = controllen;
931d865fc92SAndy Fiddaman }
932d865fc92SAndy Fiddaman }
933d865fc92SAndy Fiddaman
9347c478bd9Sstevel@tonic-gate error = copyout_arg(control, controllen, controllenp,
9357c478bd9Sstevel@tonic-gate msg->msg_control, msg->msg_controllen);
936d865fc92SAndy Fiddaman
9377c478bd9Sstevel@tonic-gate if (error)
9387c478bd9Sstevel@tonic-gate goto err;
9397c478bd9Sstevel@tonic-gate
9407c478bd9Sstevel@tonic-gate }
9417c478bd9Sstevel@tonic-gate if (msg->msg_namelen != 0)
9427c478bd9Sstevel@tonic-gate kmem_free(msg->msg_name, (size_t)msg->msg_namelen);
943d865fc92SAndy Fiddaman if (free_controllen != 0)
944d865fc92SAndy Fiddaman kmem_free(msg->msg_control, (size_t)free_controllen);
9457c478bd9Sstevel@tonic-gate return (len - uiop->uio_resid);
9467c478bd9Sstevel@tonic-gate
9477c478bd9Sstevel@tonic-gate err:
9487c478bd9Sstevel@tonic-gate /*
9497c478bd9Sstevel@tonic-gate * If we fail and the control part contains file descriptors
950d865fc92SAndy Fiddaman * we have to close them. For a truncated control message, the
951d865fc92SAndy Fiddaman * descriptors which were cut off have already been closed and the
952d865fc92SAndy Fiddaman * length adjusted so that they will not be closed again.
9537c478bd9Sstevel@tonic-gate */
9547c478bd9Sstevel@tonic-gate if (msg->msg_controllen != 0)
9557c478bd9Sstevel@tonic-gate so_closefds(msg->msg_control, msg->msg_controllen,
9567c478bd9Sstevel@tonic-gate !(flags & MSG_XPG4_2), 0);
9577c478bd9Sstevel@tonic-gate if (msg->msg_namelen != 0)
9587c478bd9Sstevel@tonic-gate kmem_free(msg->msg_name, (size_t)msg->msg_namelen);
959d865fc92SAndy Fiddaman if (free_controllen != 0)
960d865fc92SAndy Fiddaman kmem_free(msg->msg_control, (size_t)free_controllen);
9617c478bd9Sstevel@tonic-gate return (set_errno(error));
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate
9647c478bd9Sstevel@tonic-gate /*
9657c478bd9Sstevel@tonic-gate * Native system call
9667c478bd9Sstevel@tonic-gate */
9677c478bd9Sstevel@tonic-gate ssize_t
recv(int sock,void * buffer,size_t len,int flags)9687c478bd9Sstevel@tonic-gate recv(int sock, void *buffer, size_t len, int flags)
9697c478bd9Sstevel@tonic-gate {
9707c478bd9Sstevel@tonic-gate struct nmsghdr lmsg;
9717c478bd9Sstevel@tonic-gate struct uio auio;
9727c478bd9Sstevel@tonic-gate struct iovec aiov[1];
9737c478bd9Sstevel@tonic-gate
9747c478bd9Sstevel@tonic-gate dprint(1, ("recv(%d, %p, %ld, %d)\n",
975745b2690Stz sock, buffer, len, flags));
9767c478bd9Sstevel@tonic-gate
9777c478bd9Sstevel@tonic-gate if ((ssize_t)len < 0) {
9787c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
9797c478bd9Sstevel@tonic-gate }
9807c478bd9Sstevel@tonic-gate
9817c478bd9Sstevel@tonic-gate aiov[0].iov_base = buffer;
9827c478bd9Sstevel@tonic-gate aiov[0].iov_len = len;
9837c478bd9Sstevel@tonic-gate auio.uio_loffset = 0;
9847c478bd9Sstevel@tonic-gate auio.uio_iov = aiov;
9857c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1;
9867c478bd9Sstevel@tonic-gate auio.uio_resid = len;
9877c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE;
9887c478bd9Sstevel@tonic-gate auio.uio_limit = 0;
9897c478bd9Sstevel@tonic-gate
9907c478bd9Sstevel@tonic-gate lmsg.msg_namelen = 0;
9917c478bd9Sstevel@tonic-gate lmsg.msg_controllen = 0;
9927c478bd9Sstevel@tonic-gate lmsg.msg_flags = 0;
9937c478bd9Sstevel@tonic-gate return (recvit(sock, &lmsg, &auio, flags, NULL, NULL, NULL));
9947c478bd9Sstevel@tonic-gate }
9957c478bd9Sstevel@tonic-gate
9967c478bd9Sstevel@tonic-gate ssize_t
recvfrom(int sock,void * buffer,size_t len,int flags,struct sockaddr * name,socklen_t * namelenp)9978cd31312SMarcel Telka recvfrom(int sock, void *buffer, size_t len, int flags, struct sockaddr *name,
9988cd31312SMarcel Telka socklen_t *namelenp)
9997c478bd9Sstevel@tonic-gate {
10007c478bd9Sstevel@tonic-gate struct nmsghdr lmsg;
10017c478bd9Sstevel@tonic-gate struct uio auio;
10027c478bd9Sstevel@tonic-gate struct iovec aiov[1];
10037c478bd9Sstevel@tonic-gate
10047c478bd9Sstevel@tonic-gate dprint(1, ("recvfrom(%d, %p, %ld, %d, %p, %p)\n",
1005903a11ebSrh sock, buffer, len, flags, (void *)name, (void *)namelenp));
10067c478bd9Sstevel@tonic-gate
10077c478bd9Sstevel@tonic-gate if ((ssize_t)len < 0) {
10087c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate
10117c478bd9Sstevel@tonic-gate aiov[0].iov_base = buffer;
10127c478bd9Sstevel@tonic-gate aiov[0].iov_len = len;
10137c478bd9Sstevel@tonic-gate auio.uio_loffset = 0;
10147c478bd9Sstevel@tonic-gate auio.uio_iov = aiov;
10157c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1;
10167c478bd9Sstevel@tonic-gate auio.uio_resid = len;
10177c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE;
10187c478bd9Sstevel@tonic-gate auio.uio_limit = 0;
10197c478bd9Sstevel@tonic-gate
10207c478bd9Sstevel@tonic-gate lmsg.msg_name = (char *)name;
10217c478bd9Sstevel@tonic-gate if (namelenp != NULL) {
10227c478bd9Sstevel@tonic-gate if (copyin(namelenp, &lmsg.msg_namelen,
10237c478bd9Sstevel@tonic-gate sizeof (lmsg.msg_namelen)))
10247c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
10257c478bd9Sstevel@tonic-gate } else {
10267c478bd9Sstevel@tonic-gate lmsg.msg_namelen = 0;
10277c478bd9Sstevel@tonic-gate }
10287c478bd9Sstevel@tonic-gate lmsg.msg_controllen = 0;
10297c478bd9Sstevel@tonic-gate lmsg.msg_flags = 0;
10307c478bd9Sstevel@tonic-gate
10317c478bd9Sstevel@tonic-gate return (recvit(sock, &lmsg, &auio, flags, namelenp, NULL, NULL));
10327c478bd9Sstevel@tonic-gate }
10337c478bd9Sstevel@tonic-gate
10347c478bd9Sstevel@tonic-gate /*
10357c478bd9Sstevel@tonic-gate * Uses the MSG_XPG4_2 flag to determine if the caller is using
10367c478bd9Sstevel@tonic-gate * struct omsghdr or struct nmsghdr.
10377c478bd9Sstevel@tonic-gate */
10387c478bd9Sstevel@tonic-gate ssize_t
recvmsg(int sock,struct nmsghdr * msg,int flags)10397c478bd9Sstevel@tonic-gate recvmsg(int sock, struct nmsghdr *msg, int flags)
10407c478bd9Sstevel@tonic-gate {
10417c478bd9Sstevel@tonic-gate STRUCT_DECL(nmsghdr, u_lmsg);
10427c478bd9Sstevel@tonic-gate STRUCT_HANDLE(nmsghdr, umsgptr);
10437c478bd9Sstevel@tonic-gate struct nmsghdr lmsg;
10447c478bd9Sstevel@tonic-gate struct uio auio;
10458e935259SBryan Cantrill struct iovec buf[IOV_MAX_STACK], *aiov = buf;
10468e935259SBryan Cantrill ssize_t iovsize = 0;
10477c478bd9Sstevel@tonic-gate int iovcnt;
10488e935259SBryan Cantrill ssize_t len, rval;
10497c478bd9Sstevel@tonic-gate int i;
10507c478bd9Sstevel@tonic-gate int *flagsp;
10517c478bd9Sstevel@tonic-gate model_t model;
10527c478bd9Sstevel@tonic-gate
10537c478bd9Sstevel@tonic-gate dprint(1, ("recvmsg(%d, %p, %d)\n",
1054903a11ebSrh sock, (void *)msg, flags));
10557c478bd9Sstevel@tonic-gate
10567c478bd9Sstevel@tonic-gate model = get_udatamodel();
10577c478bd9Sstevel@tonic-gate STRUCT_INIT(u_lmsg, model);
10587c478bd9Sstevel@tonic-gate STRUCT_SET_HANDLE(umsgptr, model, msg);
10597c478bd9Sstevel@tonic-gate
10607c478bd9Sstevel@tonic-gate if (flags & MSG_XPG4_2) {
10617c478bd9Sstevel@tonic-gate if (copyin(msg, STRUCT_BUF(u_lmsg), STRUCT_SIZE(u_lmsg)))
10627c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
10637c478bd9Sstevel@tonic-gate flagsp = STRUCT_FADDR(umsgptr, msg_flags);
10647c478bd9Sstevel@tonic-gate } else {
10657c478bd9Sstevel@tonic-gate /*
10667c478bd9Sstevel@tonic-gate * Assumes that nmsghdr and omsghdr are identically shaped
10677c478bd9Sstevel@tonic-gate * except for the added msg_flags field.
10687c478bd9Sstevel@tonic-gate */
10697c478bd9Sstevel@tonic-gate if (copyin(msg, STRUCT_BUF(u_lmsg),
10707c478bd9Sstevel@tonic-gate SIZEOF_STRUCT(omsghdr, model)))
10717c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
10727c478bd9Sstevel@tonic-gate STRUCT_FSET(u_lmsg, msg_flags, 0);
10737c478bd9Sstevel@tonic-gate flagsp = NULL;
10747c478bd9Sstevel@tonic-gate }
10757c478bd9Sstevel@tonic-gate
10767c478bd9Sstevel@tonic-gate /*
10777c478bd9Sstevel@tonic-gate * Code below us will kmem_alloc memory and hang it
10787c478bd9Sstevel@tonic-gate * off msg_control and msg_name fields. This forces
10797c478bd9Sstevel@tonic-gate * us to copy the structure to its native form.
10807c478bd9Sstevel@tonic-gate */
10817c478bd9Sstevel@tonic-gate lmsg.msg_name = STRUCT_FGETP(u_lmsg, msg_name);
10827c478bd9Sstevel@tonic-gate lmsg.msg_namelen = STRUCT_FGET(u_lmsg, msg_namelen);
10837c478bd9Sstevel@tonic-gate lmsg.msg_iov = STRUCT_FGETP(u_lmsg, msg_iov);
10847c478bd9Sstevel@tonic-gate lmsg.msg_iovlen = STRUCT_FGET(u_lmsg, msg_iovlen);
10857c478bd9Sstevel@tonic-gate lmsg.msg_control = STRUCT_FGETP(u_lmsg, msg_control);
10867c478bd9Sstevel@tonic-gate lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen);
10877c478bd9Sstevel@tonic-gate lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags);
10887c478bd9Sstevel@tonic-gate
10897c478bd9Sstevel@tonic-gate iovcnt = lmsg.msg_iovlen;
10907c478bd9Sstevel@tonic-gate
10918e935259SBryan Cantrill if (iovcnt <= 0 || iovcnt > IOV_MAX) {
10927c478bd9Sstevel@tonic-gate return (set_errno(EMSGSIZE));
10937c478bd9Sstevel@tonic-gate }
10947c478bd9Sstevel@tonic-gate
10958e935259SBryan Cantrill if (iovcnt > IOV_MAX_STACK) {
10968e935259SBryan Cantrill iovsize = iovcnt * sizeof (struct iovec);
10978e935259SBryan Cantrill aiov = kmem_alloc(iovsize, KM_SLEEP);
10988e935259SBryan Cantrill }
10998e935259SBryan Cantrill
11007c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
11017c478bd9Sstevel@tonic-gate /*
11027c478bd9Sstevel@tonic-gate * 32-bit callers need to have their iovec expanded, while ensuring
11037c478bd9Sstevel@tonic-gate * that they can't move more than 2Gbytes of data in a single call.
11047c478bd9Sstevel@tonic-gate */
11057c478bd9Sstevel@tonic-gate if (model == DATAMODEL_ILP32) {
11068e935259SBryan Cantrill struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32;
11078e935259SBryan Cantrill ssize_t iov32size;
11087c478bd9Sstevel@tonic-gate ssize32_t count32;
11097c478bd9Sstevel@tonic-gate
11108e935259SBryan Cantrill iov32size = iovcnt * sizeof (struct iovec32);
11118e935259SBryan Cantrill if (iovsize != 0)
11128e935259SBryan Cantrill aiov32 = kmem_alloc(iov32size, KM_SLEEP);
11138e935259SBryan Cantrill
11148e935259SBryan Cantrill if (copyin((struct iovec32 *)lmsg.msg_iov, aiov32, iov32size)) {
11158e935259SBryan Cantrill if (iovsize != 0) {
11168e935259SBryan Cantrill kmem_free(aiov32, iov32size);
11178e935259SBryan Cantrill kmem_free(aiov, iovsize);
11188e935259SBryan Cantrill }
11198e935259SBryan Cantrill
11207c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
11218e935259SBryan Cantrill }
11227c478bd9Sstevel@tonic-gate
11237c478bd9Sstevel@tonic-gate count32 = 0;
11247c478bd9Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) {
11257c478bd9Sstevel@tonic-gate ssize32_t iovlen32;
11267c478bd9Sstevel@tonic-gate
11277c478bd9Sstevel@tonic-gate iovlen32 = aiov32[i].iov_len;
11287c478bd9Sstevel@tonic-gate count32 += iovlen32;
11298e935259SBryan Cantrill if (iovlen32 < 0 || count32 < 0) {
11308e935259SBryan Cantrill if (iovsize != 0) {
11318e935259SBryan Cantrill kmem_free(aiov32, iov32size);
11328e935259SBryan Cantrill kmem_free(aiov, iovsize);
11338e935259SBryan Cantrill }
11348e935259SBryan Cantrill
11357c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
11368e935259SBryan Cantrill }
11378e935259SBryan Cantrill
11387c478bd9Sstevel@tonic-gate aiov[i].iov_len = iovlen32;
11397c478bd9Sstevel@tonic-gate aiov[i].iov_base =
11407c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)aiov32[i].iov_base;
11417c478bd9Sstevel@tonic-gate }
11428e935259SBryan Cantrill
11438e935259SBryan Cantrill if (iovsize != 0)
11448e935259SBryan Cantrill kmem_free(aiov32, iov32size);
11457c478bd9Sstevel@tonic-gate } else
11467c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
11477c478bd9Sstevel@tonic-gate if (copyin(lmsg.msg_iov, aiov, iovcnt * sizeof (struct iovec))) {
11488e935259SBryan Cantrill if (iovsize != 0)
11498e935259SBryan Cantrill kmem_free(aiov, iovsize);
11508e935259SBryan Cantrill
11517c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
11527c478bd9Sstevel@tonic-gate }
11537c478bd9Sstevel@tonic-gate len = 0;
11547c478bd9Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) {
11557c478bd9Sstevel@tonic-gate ssize_t iovlen = aiov[i].iov_len;
11567c478bd9Sstevel@tonic-gate len += iovlen;
11577c478bd9Sstevel@tonic-gate if (iovlen < 0 || len < 0) {
11588e935259SBryan Cantrill if (iovsize != 0)
11598e935259SBryan Cantrill kmem_free(aiov, iovsize);
11608e935259SBryan Cantrill
11617c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
11627c478bd9Sstevel@tonic-gate }
11637c478bd9Sstevel@tonic-gate }
11647c478bd9Sstevel@tonic-gate auio.uio_loffset = 0;
11657c478bd9Sstevel@tonic-gate auio.uio_iov = aiov;
11667c478bd9Sstevel@tonic-gate auio.uio_iovcnt = iovcnt;
11677c478bd9Sstevel@tonic-gate auio.uio_resid = len;
11687c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE;
11697c478bd9Sstevel@tonic-gate auio.uio_limit = 0;
11707c478bd9Sstevel@tonic-gate
11717c478bd9Sstevel@tonic-gate if (lmsg.msg_control != NULL &&
11727c478bd9Sstevel@tonic-gate (do_useracc == 0 ||
11737c478bd9Sstevel@tonic-gate useracc(lmsg.msg_control, lmsg.msg_controllen,
1174745b2690Stz B_WRITE) != 0)) {
11758e935259SBryan Cantrill if (iovsize != 0)
11768e935259SBryan Cantrill kmem_free(aiov, iovsize);
11778e935259SBryan Cantrill
11787c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate
11818e935259SBryan Cantrill rval = recvit(sock, &lmsg, &auio, flags,
1182745b2690Stz STRUCT_FADDR(umsgptr, msg_namelen),
11838e935259SBryan Cantrill STRUCT_FADDR(umsgptr, msg_controllen), flagsp);
11848e935259SBryan Cantrill
11858e935259SBryan Cantrill if (iovsize != 0)
11868e935259SBryan Cantrill kmem_free(aiov, iovsize);
11878e935259SBryan Cantrill
11888e935259SBryan Cantrill return (rval);
11897c478bd9Sstevel@tonic-gate }
11907c478bd9Sstevel@tonic-gate
11917c478bd9Sstevel@tonic-gate /*
11927c478bd9Sstevel@tonic-gate * Common send function.
11937c478bd9Sstevel@tonic-gate */
11947c478bd9Sstevel@tonic-gate static ssize_t
sendit(int sock,struct nmsghdr * msg,struct uio * uiop,int flags)11957c478bd9Sstevel@tonic-gate sendit(int sock, struct nmsghdr *msg, struct uio *uiop, int flags)
11967c478bd9Sstevel@tonic-gate {
11977c478bd9Sstevel@tonic-gate struct sonode *so;
11987c478bd9Sstevel@tonic-gate file_t *fp;
11997c478bd9Sstevel@tonic-gate void *name;
12007c478bd9Sstevel@tonic-gate socklen_t namelen;
12017c478bd9Sstevel@tonic-gate void *control;
12027c478bd9Sstevel@tonic-gate socklen_t controllen;
12037c478bd9Sstevel@tonic-gate ssize_t len;
12047c478bd9Sstevel@tonic-gate int error;
12057c478bd9Sstevel@tonic-gate
12067c478bd9Sstevel@tonic-gate if ((so = getsonode(sock, &error, &fp)) == NULL)
12077c478bd9Sstevel@tonic-gate return (set_errno(error));
12087c478bd9Sstevel@tonic-gate
12097c478bd9Sstevel@tonic-gate uiop->uio_fmode = fp->f_flag;
12107c478bd9Sstevel@tonic-gate
12117c478bd9Sstevel@tonic-gate if (so->so_family == AF_UNIX)
12127c478bd9Sstevel@tonic-gate uiop->uio_extflg = UIO_COPY_CACHED;
12137c478bd9Sstevel@tonic-gate else
12147c478bd9Sstevel@tonic-gate uiop->uio_extflg = UIO_COPY_DEFAULT;
12157c478bd9Sstevel@tonic-gate
12167c478bd9Sstevel@tonic-gate /* Allocate and copyin name and control */
12177c478bd9Sstevel@tonic-gate name = msg->msg_name;
12187c478bd9Sstevel@tonic-gate namelen = msg->msg_namelen;
12197c478bd9Sstevel@tonic-gate if (name != NULL && namelen != 0) {
12207c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
12217c478bd9Sstevel@tonic-gate name = copyin_name(so,
1222745b2690Stz (struct sockaddr *)name,
1223745b2690Stz &namelen, &error);
12247c478bd9Sstevel@tonic-gate if (name == NULL)
12257c478bd9Sstevel@tonic-gate goto done3;
12267c478bd9Sstevel@tonic-gate /* copyin_name null terminates addresses for AF_UNIX */
12277c478bd9Sstevel@tonic-gate msg->msg_namelen = namelen;
12287c478bd9Sstevel@tonic-gate msg->msg_name = name;
12297c478bd9Sstevel@tonic-gate } else {
12307c478bd9Sstevel@tonic-gate msg->msg_name = name = NULL;
12317c478bd9Sstevel@tonic-gate msg->msg_namelen = namelen = 0;
12327c478bd9Sstevel@tonic-gate }
12337c478bd9Sstevel@tonic-gate
12347c478bd9Sstevel@tonic-gate control = msg->msg_control;
12357c478bd9Sstevel@tonic-gate controllen = msg->msg_controllen;
12367c478bd9Sstevel@tonic-gate if ((control != NULL) && (controllen != 0)) {
12377c478bd9Sstevel@tonic-gate /*
12387c478bd9Sstevel@tonic-gate * Verify that the length is not excessive to prevent
12397c478bd9Sstevel@tonic-gate * an application from consuming all of kernel memory.
12407c478bd9Sstevel@tonic-gate */
12417c478bd9Sstevel@tonic-gate if (controllen > SO_MAXARGSIZE) {
12427c478bd9Sstevel@tonic-gate error = EINVAL;
12437c478bd9Sstevel@tonic-gate goto done2;
12447c478bd9Sstevel@tonic-gate }
12457c478bd9Sstevel@tonic-gate control = kmem_alloc(controllen, KM_SLEEP);
12467c478bd9Sstevel@tonic-gate
12477c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
12487c478bd9Sstevel@tonic-gate if (copyin(msg->msg_control, control, controllen)) {
12497c478bd9Sstevel@tonic-gate error = EFAULT;
12507c478bd9Sstevel@tonic-gate goto done1;
12517c478bd9Sstevel@tonic-gate }
12527c478bd9Sstevel@tonic-gate msg->msg_control = control;
12537c478bd9Sstevel@tonic-gate } else {
12547c478bd9Sstevel@tonic-gate msg->msg_control = control = NULL;
12557c478bd9Sstevel@tonic-gate msg->msg_controllen = controllen = 0;
12567c478bd9Sstevel@tonic-gate }
12577c478bd9Sstevel@tonic-gate
12587c478bd9Sstevel@tonic-gate len = uiop->uio_resid;
12597c478bd9Sstevel@tonic-gate msg->msg_flags = flags;
12607c478bd9Sstevel@tonic-gate
12610f1702c5SYu Xiangning error = socket_sendmsg(so, msg, uiop, CRED());
12627c478bd9Sstevel@tonic-gate done1:
12637c478bd9Sstevel@tonic-gate if (control != NULL)
12647c478bd9Sstevel@tonic-gate kmem_free(control, controllen);
12657c478bd9Sstevel@tonic-gate done2:
12667c478bd9Sstevel@tonic-gate if (name != NULL)
12677c478bd9Sstevel@tonic-gate kmem_free(name, namelen);
12687c478bd9Sstevel@tonic-gate done3:
12697c478bd9Sstevel@tonic-gate if (error != 0) {
12707c478bd9Sstevel@tonic-gate releasef(sock);
12717c478bd9Sstevel@tonic-gate return (set_errno(error));
12727c478bd9Sstevel@tonic-gate }
12737c478bd9Sstevel@tonic-gate lwp_stat_update(LWP_STAT_MSGSND, 1);
12747c478bd9Sstevel@tonic-gate releasef(sock);
12757c478bd9Sstevel@tonic-gate return (len - uiop->uio_resid);
12767c478bd9Sstevel@tonic-gate }
12777c478bd9Sstevel@tonic-gate
12787c478bd9Sstevel@tonic-gate /*
12797c478bd9Sstevel@tonic-gate * Native system call
12807c478bd9Sstevel@tonic-gate */
12817c478bd9Sstevel@tonic-gate ssize_t
send(int sock,void * buffer,size_t len,int flags)12827c478bd9Sstevel@tonic-gate send(int sock, void *buffer, size_t len, int flags)
12837c478bd9Sstevel@tonic-gate {
12847c478bd9Sstevel@tonic-gate struct nmsghdr lmsg;
12857c478bd9Sstevel@tonic-gate struct uio auio;
12867c478bd9Sstevel@tonic-gate struct iovec aiov[1];
12877c478bd9Sstevel@tonic-gate
12887c478bd9Sstevel@tonic-gate dprint(1, ("send(%d, %p, %ld, %d)\n",
1289745b2690Stz sock, buffer, len, flags));
12907c478bd9Sstevel@tonic-gate
12917c478bd9Sstevel@tonic-gate if ((ssize_t)len < 0) {
12927c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
12937c478bd9Sstevel@tonic-gate }
12947c478bd9Sstevel@tonic-gate
12957c478bd9Sstevel@tonic-gate aiov[0].iov_base = buffer;
12967c478bd9Sstevel@tonic-gate aiov[0].iov_len = len;
12977c478bd9Sstevel@tonic-gate auio.uio_loffset = 0;
12987c478bd9Sstevel@tonic-gate auio.uio_iov = aiov;
12997c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1;
13007c478bd9Sstevel@tonic-gate auio.uio_resid = len;
13017c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE;
13027c478bd9Sstevel@tonic-gate auio.uio_limit = 0;
13037c478bd9Sstevel@tonic-gate
13047c478bd9Sstevel@tonic-gate lmsg.msg_name = NULL;
13057c478bd9Sstevel@tonic-gate lmsg.msg_control = NULL;
13067c478bd9Sstevel@tonic-gate if (!(flags & MSG_XPG4_2)) {
13077c478bd9Sstevel@tonic-gate /*
13087c478bd9Sstevel@tonic-gate * In order to be compatible with the libsocket/sockmod
13097c478bd9Sstevel@tonic-gate * implementation we set EOR for all send* calls.
13107c478bd9Sstevel@tonic-gate */
13117c478bd9Sstevel@tonic-gate flags |= MSG_EOR;
13127c478bd9Sstevel@tonic-gate }
13137c478bd9Sstevel@tonic-gate return (sendit(sock, &lmsg, &auio, flags));
13147c478bd9Sstevel@tonic-gate }
13157c478bd9Sstevel@tonic-gate
13167c478bd9Sstevel@tonic-gate /*
13177c478bd9Sstevel@tonic-gate * Uses the MSG_XPG4_2 flag to determine if the caller is using
13187c478bd9Sstevel@tonic-gate * struct omsghdr or struct nmsghdr.
13197c478bd9Sstevel@tonic-gate */
13207c478bd9Sstevel@tonic-gate ssize_t
sendmsg(int sock,struct nmsghdr * msg,int flags)13217c478bd9Sstevel@tonic-gate sendmsg(int sock, struct nmsghdr *msg, int flags)
13227c478bd9Sstevel@tonic-gate {
13237c478bd9Sstevel@tonic-gate struct nmsghdr lmsg;
13247c478bd9Sstevel@tonic-gate STRUCT_DECL(nmsghdr, u_lmsg);
13257c478bd9Sstevel@tonic-gate struct uio auio;
13268e935259SBryan Cantrill struct iovec buf[IOV_MAX_STACK], *aiov = buf;
13278e935259SBryan Cantrill ssize_t iovsize = 0;
13287c478bd9Sstevel@tonic-gate int iovcnt;
13298e935259SBryan Cantrill ssize_t len, rval;
13307c478bd9Sstevel@tonic-gate int i;
13317c478bd9Sstevel@tonic-gate model_t model;
13327c478bd9Sstevel@tonic-gate
1333903a11ebSrh dprint(1, ("sendmsg(%d, %p, %d)\n", sock, (void *)msg, flags));
13347c478bd9Sstevel@tonic-gate
13357c478bd9Sstevel@tonic-gate model = get_udatamodel();
13367c478bd9Sstevel@tonic-gate STRUCT_INIT(u_lmsg, model);
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate if (flags & MSG_XPG4_2) {
13397c478bd9Sstevel@tonic-gate if (copyin(msg, (char *)STRUCT_BUF(u_lmsg),
13407c478bd9Sstevel@tonic-gate STRUCT_SIZE(u_lmsg)))
13417c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
13427c478bd9Sstevel@tonic-gate } else {
13437c478bd9Sstevel@tonic-gate /*
13447c478bd9Sstevel@tonic-gate * Assumes that nmsghdr and omsghdr are identically shaped
13457c478bd9Sstevel@tonic-gate * except for the added msg_flags field.
13467c478bd9Sstevel@tonic-gate */
13477c478bd9Sstevel@tonic-gate if (copyin(msg, (char *)STRUCT_BUF(u_lmsg),
13487c478bd9Sstevel@tonic-gate SIZEOF_STRUCT(omsghdr, model)))
13497c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
13507c478bd9Sstevel@tonic-gate /*
13517c478bd9Sstevel@tonic-gate * In order to be compatible with the libsocket/sockmod
13527c478bd9Sstevel@tonic-gate * implementation we set EOR for all send* calls.
13537c478bd9Sstevel@tonic-gate */
13547c478bd9Sstevel@tonic-gate flags |= MSG_EOR;
13557c478bd9Sstevel@tonic-gate }
13567c478bd9Sstevel@tonic-gate
13577c478bd9Sstevel@tonic-gate /*
13587c478bd9Sstevel@tonic-gate * Code below us will kmem_alloc memory and hang it
13597c478bd9Sstevel@tonic-gate * off msg_control and msg_name fields. This forces
13607c478bd9Sstevel@tonic-gate * us to copy the structure to its native form.
13617c478bd9Sstevel@tonic-gate */
13627c478bd9Sstevel@tonic-gate lmsg.msg_name = STRUCT_FGETP(u_lmsg, msg_name);
13637c478bd9Sstevel@tonic-gate lmsg.msg_namelen = STRUCT_FGET(u_lmsg, msg_namelen);
13647c478bd9Sstevel@tonic-gate lmsg.msg_iov = STRUCT_FGETP(u_lmsg, msg_iov);
13657c478bd9Sstevel@tonic-gate lmsg.msg_iovlen = STRUCT_FGET(u_lmsg, msg_iovlen);
13667c478bd9Sstevel@tonic-gate lmsg.msg_control = STRUCT_FGETP(u_lmsg, msg_control);
13677c478bd9Sstevel@tonic-gate lmsg.msg_controllen = STRUCT_FGET(u_lmsg, msg_controllen);
13687c478bd9Sstevel@tonic-gate lmsg.msg_flags = STRUCT_FGET(u_lmsg, msg_flags);
13697c478bd9Sstevel@tonic-gate
13707c478bd9Sstevel@tonic-gate iovcnt = lmsg.msg_iovlen;
13717c478bd9Sstevel@tonic-gate
13728e935259SBryan Cantrill if (iovcnt <= 0 || iovcnt > IOV_MAX) {
13737c478bd9Sstevel@tonic-gate /*
13747c478bd9Sstevel@tonic-gate * Unless this is XPG 4.2 we allow iovcnt == 0 to
13757c478bd9Sstevel@tonic-gate * be compatible with SunOS 4.X and 4.4BSD.
13767c478bd9Sstevel@tonic-gate */
13777c478bd9Sstevel@tonic-gate if (iovcnt != 0 || (flags & MSG_XPG4_2))
13787c478bd9Sstevel@tonic-gate return (set_errno(EMSGSIZE));
13797c478bd9Sstevel@tonic-gate }
13807c478bd9Sstevel@tonic-gate
13818e935259SBryan Cantrill if (iovcnt > IOV_MAX_STACK) {
13828e935259SBryan Cantrill iovsize = iovcnt * sizeof (struct iovec);
13838e935259SBryan Cantrill aiov = kmem_alloc(iovsize, KM_SLEEP);
13848e935259SBryan Cantrill }
13858e935259SBryan Cantrill
13867c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
13877c478bd9Sstevel@tonic-gate /*
13887c478bd9Sstevel@tonic-gate * 32-bit callers need to have their iovec expanded, while ensuring
13897c478bd9Sstevel@tonic-gate * that they can't move more than 2Gbytes of data in a single call.
13907c478bd9Sstevel@tonic-gate */
13917c478bd9Sstevel@tonic-gate if (model == DATAMODEL_ILP32) {
13928e935259SBryan Cantrill struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32;
13938e935259SBryan Cantrill ssize_t iov32size;
13947c478bd9Sstevel@tonic-gate ssize32_t count32;
13957c478bd9Sstevel@tonic-gate
13968e935259SBryan Cantrill iov32size = iovcnt * sizeof (struct iovec32);
13978e935259SBryan Cantrill if (iovsize != 0)
13988e935259SBryan Cantrill aiov32 = kmem_alloc(iov32size, KM_SLEEP);
13998e935259SBryan Cantrill
14007c478bd9Sstevel@tonic-gate if (iovcnt != 0 &&
14018e935259SBryan Cantrill copyin((struct iovec32 *)lmsg.msg_iov, aiov32, iov32size)) {
14028e935259SBryan Cantrill if (iovsize != 0) {
14038e935259SBryan Cantrill kmem_free(aiov32, iov32size);
14048e935259SBryan Cantrill kmem_free(aiov, iovsize);
14058e935259SBryan Cantrill }
14068e935259SBryan Cantrill
14077c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
14088e935259SBryan Cantrill }
14097c478bd9Sstevel@tonic-gate
14107c478bd9Sstevel@tonic-gate count32 = 0;
14117c478bd9Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) {
14127c478bd9Sstevel@tonic-gate ssize32_t iovlen32;
14137c478bd9Sstevel@tonic-gate
14147c478bd9Sstevel@tonic-gate iovlen32 = aiov32[i].iov_len;
14157c478bd9Sstevel@tonic-gate count32 += iovlen32;
14168e935259SBryan Cantrill if (iovlen32 < 0 || count32 < 0) {
14178e935259SBryan Cantrill if (iovsize != 0) {
14188e935259SBryan Cantrill kmem_free(aiov32, iov32size);
14198e935259SBryan Cantrill kmem_free(aiov, iovsize);
14208e935259SBryan Cantrill }
14218e935259SBryan Cantrill
14227c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
14238e935259SBryan Cantrill }
14248e935259SBryan Cantrill
14257c478bd9Sstevel@tonic-gate aiov[i].iov_len = iovlen32;
14267c478bd9Sstevel@tonic-gate aiov[i].iov_base =
14277c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)aiov32[i].iov_base;
14287c478bd9Sstevel@tonic-gate }
14298e935259SBryan Cantrill
14308e935259SBryan Cantrill if (iovsize != 0)
14318e935259SBryan Cantrill kmem_free(aiov32, iov32size);
14327c478bd9Sstevel@tonic-gate } else
14337c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
14347c478bd9Sstevel@tonic-gate if (iovcnt != 0 &&
14357c478bd9Sstevel@tonic-gate copyin(lmsg.msg_iov, aiov,
14367c478bd9Sstevel@tonic-gate (unsigned)iovcnt * sizeof (struct iovec))) {
14378e935259SBryan Cantrill if (iovsize != 0)
14388e935259SBryan Cantrill kmem_free(aiov, iovsize);
14398e935259SBryan Cantrill
14407c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
14417c478bd9Sstevel@tonic-gate }
14427c478bd9Sstevel@tonic-gate len = 0;
14437c478bd9Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) {
14447c478bd9Sstevel@tonic-gate ssize_t iovlen = aiov[i].iov_len;
14457c478bd9Sstevel@tonic-gate len += iovlen;
14467c478bd9Sstevel@tonic-gate if (iovlen < 0 || len < 0) {
14478e935259SBryan Cantrill if (iovsize != 0)
14488e935259SBryan Cantrill kmem_free(aiov, iovsize);
14498e935259SBryan Cantrill
14507c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
14517c478bd9Sstevel@tonic-gate }
14527c478bd9Sstevel@tonic-gate }
14537c478bd9Sstevel@tonic-gate auio.uio_loffset = 0;
14547c478bd9Sstevel@tonic-gate auio.uio_iov = aiov;
14557c478bd9Sstevel@tonic-gate auio.uio_iovcnt = iovcnt;
14567c478bd9Sstevel@tonic-gate auio.uio_resid = len;
14577c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE;
14587c478bd9Sstevel@tonic-gate auio.uio_limit = 0;
14597c478bd9Sstevel@tonic-gate
14608e935259SBryan Cantrill rval = sendit(sock, &lmsg, &auio, flags);
14618e935259SBryan Cantrill
14628e935259SBryan Cantrill if (iovsize != 0)
14638e935259SBryan Cantrill kmem_free(aiov, iovsize);
14648e935259SBryan Cantrill
14658e935259SBryan Cantrill return (rval);
14667c478bd9Sstevel@tonic-gate }
14677c478bd9Sstevel@tonic-gate
14687c478bd9Sstevel@tonic-gate ssize_t
sendto(int sock,void * buffer,size_t len,int flags,struct sockaddr * name,socklen_t namelen)14697c478bd9Sstevel@tonic-gate sendto(int sock, void *buffer, size_t len, int flags,
14707c478bd9Sstevel@tonic-gate struct sockaddr *name, socklen_t namelen)
14717c478bd9Sstevel@tonic-gate {
14727c478bd9Sstevel@tonic-gate struct nmsghdr lmsg;
14737c478bd9Sstevel@tonic-gate struct uio auio;
14747c478bd9Sstevel@tonic-gate struct iovec aiov[1];
14757c478bd9Sstevel@tonic-gate
14767c478bd9Sstevel@tonic-gate dprint(1, ("sendto(%d, %p, %ld, %d, %p, %d)\n",
1477903a11ebSrh sock, buffer, len, flags, (void *)name, namelen));
14787c478bd9Sstevel@tonic-gate
14797c478bd9Sstevel@tonic-gate if ((ssize_t)len < 0) {
14807c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
14817c478bd9Sstevel@tonic-gate }
14827c478bd9Sstevel@tonic-gate
14837c478bd9Sstevel@tonic-gate aiov[0].iov_base = buffer;
14847c478bd9Sstevel@tonic-gate aiov[0].iov_len = len;
14857c478bd9Sstevel@tonic-gate auio.uio_loffset = 0;
14867c478bd9Sstevel@tonic-gate auio.uio_iov = aiov;
14877c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1;
14887c478bd9Sstevel@tonic-gate auio.uio_resid = len;
14897c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE;
14907c478bd9Sstevel@tonic-gate auio.uio_limit = 0;
14917c478bd9Sstevel@tonic-gate
14927c478bd9Sstevel@tonic-gate lmsg.msg_name = (char *)name;
14937c478bd9Sstevel@tonic-gate lmsg.msg_namelen = namelen;
14947c478bd9Sstevel@tonic-gate lmsg.msg_control = NULL;
14957c478bd9Sstevel@tonic-gate if (!(flags & MSG_XPG4_2)) {
14967c478bd9Sstevel@tonic-gate /*
14977c478bd9Sstevel@tonic-gate * In order to be compatible with the libsocket/sockmod
14987c478bd9Sstevel@tonic-gate * implementation we set EOR for all send* calls.
14997c478bd9Sstevel@tonic-gate */
15007c478bd9Sstevel@tonic-gate flags |= MSG_EOR;
15017c478bd9Sstevel@tonic-gate }
15027c478bd9Sstevel@tonic-gate return (sendit(sock, &lmsg, &auio, flags));
15037c478bd9Sstevel@tonic-gate }
15047c478bd9Sstevel@tonic-gate
15057c478bd9Sstevel@tonic-gate /*ARGSUSED3*/
15067c478bd9Sstevel@tonic-gate int
getpeername(int sock,struct sockaddr * name,socklen_t * namelenp,int version)15077c478bd9Sstevel@tonic-gate getpeername(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
15087c478bd9Sstevel@tonic-gate {
15097c478bd9Sstevel@tonic-gate struct sonode *so;
15107c478bd9Sstevel@tonic-gate int error;
15117c478bd9Sstevel@tonic-gate socklen_t namelen;
15120f1702c5SYu Xiangning socklen_t sock_addrlen;
15130f1702c5SYu Xiangning struct sockaddr *sock_addrp;
15147c478bd9Sstevel@tonic-gate
15157c478bd9Sstevel@tonic-gate dprint(1, ("getpeername(%d, %p, %p)\n",
1516903a11ebSrh sock, (void *)name, (void *)namelenp));
15177c478bd9Sstevel@tonic-gate
15187c478bd9Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
15197c478bd9Sstevel@tonic-gate goto bad;
15207c478bd9Sstevel@tonic-gate
15217c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
15227c478bd9Sstevel@tonic-gate if (copyin(namelenp, &namelen, sizeof (namelen)) ||
15237c478bd9Sstevel@tonic-gate (name == NULL && namelen != 0)) {
15247c478bd9Sstevel@tonic-gate error = EFAULT;
15257c478bd9Sstevel@tonic-gate goto rel_out;
15267c478bd9Sstevel@tonic-gate }
15270f1702c5SYu Xiangning sock_addrlen = so->so_max_addr_len;
15280f1702c5SYu Xiangning sock_addrp = (struct sockaddr *)kmem_alloc(sock_addrlen, KM_SLEEP);
15297c478bd9Sstevel@tonic-gate
15300f1702c5SYu Xiangning if ((error = socket_getpeername(so, sock_addrp, &sock_addrlen,
15310f1702c5SYu Xiangning B_FALSE, CRED())) == 0) {
15320f1702c5SYu Xiangning ASSERT(sock_addrlen <= so->so_max_addr_len);
15330f1702c5SYu Xiangning error = copyout_name(name, namelen, namelenp,
15340f1702c5SYu Xiangning (void *)sock_addrp, sock_addrlen);
15357c478bd9Sstevel@tonic-gate }
15360f1702c5SYu Xiangning kmem_free(sock_addrp, so->so_max_addr_len);
15377c478bd9Sstevel@tonic-gate rel_out:
15387c478bd9Sstevel@tonic-gate releasef(sock);
15397c478bd9Sstevel@tonic-gate bad: return (error != 0 ? set_errno(error) : 0);
15407c478bd9Sstevel@tonic-gate }
15417c478bd9Sstevel@tonic-gate
15427c478bd9Sstevel@tonic-gate /*ARGSUSED3*/
15437c478bd9Sstevel@tonic-gate int
getsockname(int sock,struct sockaddr * name,socklen_t * namelenp,int version)15448cd31312SMarcel Telka getsockname(int sock, struct sockaddr *name, socklen_t *namelenp, int version)
15457c478bd9Sstevel@tonic-gate {
15467c478bd9Sstevel@tonic-gate struct sonode *so;
15477c478bd9Sstevel@tonic-gate int error;
15480f1702c5SYu Xiangning socklen_t namelen, sock_addrlen;
15490f1702c5SYu Xiangning struct sockaddr *sock_addrp;
15507c478bd9Sstevel@tonic-gate
15517c478bd9Sstevel@tonic-gate dprint(1, ("getsockname(%d, %p, %p)\n",
1552903a11ebSrh sock, (void *)name, (void *)namelenp));
15537c478bd9Sstevel@tonic-gate
15547c478bd9Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
15557c478bd9Sstevel@tonic-gate goto bad;
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
15587c478bd9Sstevel@tonic-gate if (copyin(namelenp, &namelen, sizeof (namelen)) ||
15597c478bd9Sstevel@tonic-gate (name == NULL && namelen != 0)) {
15607c478bd9Sstevel@tonic-gate error = EFAULT;
15617c478bd9Sstevel@tonic-gate goto rel_out;
15627c478bd9Sstevel@tonic-gate }
15637c478bd9Sstevel@tonic-gate
15640f1702c5SYu Xiangning sock_addrlen = so->so_max_addr_len;
15650f1702c5SYu Xiangning sock_addrp = (struct sockaddr *)kmem_alloc(sock_addrlen, KM_SLEEP);
15660f1702c5SYu Xiangning if ((error = socket_getsockname(so, sock_addrp, &sock_addrlen,
15670f1702c5SYu Xiangning CRED())) == 0) {
15680f1702c5SYu Xiangning ASSERT(MUTEX_NOT_HELD(&so->so_lock));
15690f1702c5SYu Xiangning ASSERT(sock_addrlen <= so->so_max_addr_len);
15700f1702c5SYu Xiangning error = copyout_name(name, namelen, namelenp,
15710f1702c5SYu Xiangning (void *)sock_addrp, sock_addrlen);
15727c478bd9Sstevel@tonic-gate }
15730f1702c5SYu Xiangning kmem_free(sock_addrp, so->so_max_addr_len);
15747c478bd9Sstevel@tonic-gate rel_out:
15757c478bd9Sstevel@tonic-gate releasef(sock);
15767c478bd9Sstevel@tonic-gate bad: return (error != 0 ? set_errno(error) : 0);
15777c478bd9Sstevel@tonic-gate }
15787c478bd9Sstevel@tonic-gate
15797c478bd9Sstevel@tonic-gate /*ARGSUSED5*/
15807c478bd9Sstevel@tonic-gate int
getsockopt(int sock,int level,int option_name,void * option_value,socklen_t * option_lenp,int version)15818cd31312SMarcel Telka getsockopt(int sock, int level, int option_name, void *option_value,
15828cd31312SMarcel Telka socklen_t *option_lenp, int version)
15837c478bd9Sstevel@tonic-gate {
15847c478bd9Sstevel@tonic-gate struct sonode *so;
15857c478bd9Sstevel@tonic-gate socklen_t optlen, optlen_res;
15867c478bd9Sstevel@tonic-gate void *optval;
15877c478bd9Sstevel@tonic-gate int error;
15887c478bd9Sstevel@tonic-gate
15897c478bd9Sstevel@tonic-gate dprint(1, ("getsockopt(%d, %d, %d, %p, %p)\n",
1590903a11ebSrh sock, level, option_name, option_value, (void *)option_lenp));
15917c478bd9Sstevel@tonic-gate
15927c478bd9Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
15937c478bd9Sstevel@tonic-gate return (set_errno(error));
15947c478bd9Sstevel@tonic-gate
15957c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
15967c478bd9Sstevel@tonic-gate if (copyin(option_lenp, &optlen, sizeof (optlen))) {
15977c478bd9Sstevel@tonic-gate releasef(sock);
15987c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
15997c478bd9Sstevel@tonic-gate }
16007c478bd9Sstevel@tonic-gate /*
16017c478bd9Sstevel@tonic-gate * Verify that the length is not excessive to prevent
16027c478bd9Sstevel@tonic-gate * an application from consuming all of kernel memory.
16037c478bd9Sstevel@tonic-gate */
16047c478bd9Sstevel@tonic-gate if (optlen > SO_MAXARGSIZE) {
16057c478bd9Sstevel@tonic-gate error = EINVAL;
16067c478bd9Sstevel@tonic-gate releasef(sock);
16077c478bd9Sstevel@tonic-gate return (set_errno(error));
16087c478bd9Sstevel@tonic-gate }
16097c478bd9Sstevel@tonic-gate optval = kmem_alloc(optlen, KM_SLEEP);
16107c478bd9Sstevel@tonic-gate optlen_res = optlen;
16110f1702c5SYu Xiangning error = socket_getsockopt(so, level, option_name, optval,
16120f1702c5SYu Xiangning &optlen_res, (version != SOV_XPG4_2) ? 0 : _SOGETSOCKOPT_XPG4_2,
16130f1702c5SYu Xiangning CRED());
16147c478bd9Sstevel@tonic-gate releasef(sock);
16157c478bd9Sstevel@tonic-gate if (error) {
16167c478bd9Sstevel@tonic-gate kmem_free(optval, optlen);
16177c478bd9Sstevel@tonic-gate return (set_errno(error));
16187c478bd9Sstevel@tonic-gate }
16197c478bd9Sstevel@tonic-gate error = copyout_arg(option_value, optlen, option_lenp,
16207c478bd9Sstevel@tonic-gate optval, optlen_res);
16217c478bd9Sstevel@tonic-gate kmem_free(optval, optlen);
16227c478bd9Sstevel@tonic-gate if (error)
16237c478bd9Sstevel@tonic-gate return (set_errno(error));
16247c478bd9Sstevel@tonic-gate return (0);
16257c478bd9Sstevel@tonic-gate }
16267c478bd9Sstevel@tonic-gate
16277c478bd9Sstevel@tonic-gate /*ARGSUSED5*/
16287c478bd9Sstevel@tonic-gate int
setsockopt(int sock,int level,int option_name,void * option_value,socklen_t option_len,int version)16298cd31312SMarcel Telka setsockopt(int sock, int level, int option_name, void *option_value,
16308cd31312SMarcel Telka socklen_t option_len, int version)
16317c478bd9Sstevel@tonic-gate {
16327c478bd9Sstevel@tonic-gate struct sonode *so;
16337c478bd9Sstevel@tonic-gate intptr_t buffer[2];
16347c478bd9Sstevel@tonic-gate void *optval = NULL;
16357c478bd9Sstevel@tonic-gate int error;
16367c478bd9Sstevel@tonic-gate
16377c478bd9Sstevel@tonic-gate dprint(1, ("setsockopt(%d, %d, %d, %p, %d)\n",
1638745b2690Stz sock, level, option_name, option_value, option_len));
16397c478bd9Sstevel@tonic-gate
16407c478bd9Sstevel@tonic-gate if ((so = getsonode(sock, &error, NULL)) == NULL)
16417c478bd9Sstevel@tonic-gate return (set_errno(error));
16427c478bd9Sstevel@tonic-gate
16437c478bd9Sstevel@tonic-gate if (option_value != NULL) {
16447c478bd9Sstevel@tonic-gate if (option_len != 0) {
16457c478bd9Sstevel@tonic-gate /*
16467c478bd9Sstevel@tonic-gate * Verify that the length is not excessive to prevent
16477c478bd9Sstevel@tonic-gate * an application from consuming all of kernel memory.
16487c478bd9Sstevel@tonic-gate */
16497c478bd9Sstevel@tonic-gate if (option_len > SO_MAXARGSIZE) {
16507c478bd9Sstevel@tonic-gate error = EINVAL;
16517c478bd9Sstevel@tonic-gate goto done2;
16527c478bd9Sstevel@tonic-gate }
16537c478bd9Sstevel@tonic-gate optval = option_len <= sizeof (buffer) ?
16547c478bd9Sstevel@tonic-gate &buffer : kmem_alloc((size_t)option_len, KM_SLEEP);
16557c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&so->so_lock));
16567c478bd9Sstevel@tonic-gate if (copyin(option_value, optval, (size_t)option_len)) {
16577c478bd9Sstevel@tonic-gate error = EFAULT;
16587c478bd9Sstevel@tonic-gate goto done1;
16597c478bd9Sstevel@tonic-gate }
16607c478bd9Sstevel@tonic-gate }
16617c478bd9Sstevel@tonic-gate } else
16627c478bd9Sstevel@tonic-gate option_len = 0;
16637c478bd9Sstevel@tonic-gate
16640f1702c5SYu Xiangning error = socket_setsockopt(so, level, option_name, optval,
16650f1702c5SYu Xiangning (t_uscalar_t)option_len, CRED());
16667c478bd9Sstevel@tonic-gate done1:
16677c478bd9Sstevel@tonic-gate if (optval != buffer)
16687c478bd9Sstevel@tonic-gate kmem_free(optval, (size_t)option_len);
16697c478bd9Sstevel@tonic-gate done2:
16707c478bd9Sstevel@tonic-gate releasef(sock);
16717c478bd9Sstevel@tonic-gate if (error)
16727c478bd9Sstevel@tonic-gate return (set_errno(error));
16737c478bd9Sstevel@tonic-gate return (0);
16747c478bd9Sstevel@tonic-gate }
16757c478bd9Sstevel@tonic-gate
16763e95bd4aSAnders Persson static int
sockconf_add_sock(int family,int type,int protocol,char * name)16773e95bd4aSAnders Persson sockconf_add_sock(int family, int type, int protocol, char *name)
16787c478bd9Sstevel@tonic-gate {
16793e95bd4aSAnders Persson int error = 0;
16803e95bd4aSAnders Persson char *kdevpath = NULL;
16810f1702c5SYu Xiangning char *kmodule = NULL;
16823e95bd4aSAnders Persson char *buf = NULL;
16830f1702c5SYu Xiangning size_t pathlen = 0;
16843e95bd4aSAnders Persson struct sockparams *sp;
16857c478bd9Sstevel@tonic-gate
16863e95bd4aSAnders Persson if (name == NULL)
16873e95bd4aSAnders Persson return (EINVAL);
16880f1702c5SYu Xiangning /*
16893e95bd4aSAnders Persson * Copyin the name.
16903e95bd4aSAnders Persson * This also makes it possible to check for too long pathnames.
16913e95bd4aSAnders Persson * Compress the space needed for the name before passing it
16923e95bd4aSAnders Persson * to soconfig - soconfig will store the string until
16933e95bd4aSAnders Persson * the configuration is removed.
16940f1702c5SYu Xiangning */
16953e95bd4aSAnders Persson buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
16963e95bd4aSAnders Persson if ((error = copyinstr(name, buf, MAXPATHLEN, &pathlen)) != 0) {
16973e95bd4aSAnders Persson kmem_free(buf, MAXPATHLEN);
16983e95bd4aSAnders Persson return (error);
16993e95bd4aSAnders Persson }
17003e95bd4aSAnders Persson if (strncmp(buf, "/dev", strlen("/dev")) == 0) {
17013e95bd4aSAnders Persson /* For device */
170215f90b02SGarrett D'Amore kdevpath = kmem_alloc(pathlen, KM_SLEEP);
170315f90b02SGarrett D'Amore bcopy(buf, kdevpath, pathlen);
170415f90b02SGarrett D'Amore kdevpath[pathlen - 1] = '\0';
17053e95bd4aSAnders Persson } else {
17063e95bd4aSAnders Persson /* For socket module */
17073e95bd4aSAnders Persson kmodule = kmem_alloc(pathlen, KM_SLEEP);
17083e95bd4aSAnders Persson bcopy(buf, kmodule, pathlen);
17093e95bd4aSAnders Persson kmodule[pathlen - 1] = '\0';
17103e95bd4aSAnders Persson pathlen = 0;
17113e95bd4aSAnders Persson }
17123e95bd4aSAnders Persson kmem_free(buf, MAXPATHLEN);
17137c478bd9Sstevel@tonic-gate
17143e95bd4aSAnders Persson /* sockparams_create frees mod name and devpath upon failure */
17153e95bd4aSAnders Persson sp = sockparams_create(family, type, protocol, kmodule,
17163e95bd4aSAnders Persson kdevpath, pathlen, 0, KM_SLEEP, &error);
17173e95bd4aSAnders Persson if (sp != NULL) {
17183e95bd4aSAnders Persson error = sockparams_add(sp);
17193e95bd4aSAnders Persson if (error != 0)
17203e95bd4aSAnders Persson sockparams_destroy(sp);
17213e95bd4aSAnders Persson }
17220f1702c5SYu Xiangning
17233e95bd4aSAnders Persson return (error);
17243e95bd4aSAnders Persson }
17253e95bd4aSAnders Persson
17263e95bd4aSAnders Persson static int
sockconf_remove_sock(int family,int type,int protocol)17273e95bd4aSAnders Persson sockconf_remove_sock(int family, int type, int protocol)
17283e95bd4aSAnders Persson {
17293e95bd4aSAnders Persson return (sockparams_delete(family, type, protocol));
17303e95bd4aSAnders Persson }
17313e95bd4aSAnders Persson
17323e95bd4aSAnders Persson static int
sockconfig_remove_filter(const char * uname)17333e95bd4aSAnders Persson sockconfig_remove_filter(const char *uname)
17343e95bd4aSAnders Persson {
17353e95bd4aSAnders Persson char kname[SOF_MAXNAMELEN];
17363e95bd4aSAnders Persson size_t len;
17373e95bd4aSAnders Persson int error;
17383e95bd4aSAnders Persson sof_entry_t *ent;
17393e95bd4aSAnders Persson
17403e95bd4aSAnders Persson if ((error = copyinstr(uname, kname, SOF_MAXNAMELEN, &len)) != 0)
17413e95bd4aSAnders Persson return (error);
17423e95bd4aSAnders Persson
17433e95bd4aSAnders Persson ent = sof_entry_remove_by_name(kname);
17443e95bd4aSAnders Persson if (ent == NULL)
17453e95bd4aSAnders Persson return (ENXIO);
17463e95bd4aSAnders Persson
17473e95bd4aSAnders Persson mutex_enter(&ent->sofe_lock);
17483e95bd4aSAnders Persson ASSERT(!(ent->sofe_flags & SOFEF_CONDEMED));
17493e95bd4aSAnders Persson if (ent->sofe_refcnt == 0) {
17503e95bd4aSAnders Persson mutex_exit(&ent->sofe_lock);
17513e95bd4aSAnders Persson sof_entry_free(ent);
17523e95bd4aSAnders Persson } else {
17533e95bd4aSAnders Persson /* let the last socket free the filter */
17543e95bd4aSAnders Persson ent->sofe_flags |= SOFEF_CONDEMED;
17553e95bd4aSAnders Persson mutex_exit(&ent->sofe_lock);
17563e95bd4aSAnders Persson }
17573e95bd4aSAnders Persson
17583e95bd4aSAnders Persson return (0);
17593e95bd4aSAnders Persson }
17603e95bd4aSAnders Persson
17613e95bd4aSAnders Persson static int
sockconfig_add_filter(const char * uname,void * ufilpropp)17623e95bd4aSAnders Persson sockconfig_add_filter(const char *uname, void *ufilpropp)
17633e95bd4aSAnders Persson {
17643e95bd4aSAnders Persson struct sockconfig_filter_props filprop;
17653e95bd4aSAnders Persson sof_entry_t *ent;
17663e95bd4aSAnders Persson int error;
17673e95bd4aSAnders Persson size_t tuplesz, len;
17683e95bd4aSAnders Persson char hintbuf[SOF_MAXNAMELEN];
17693e95bd4aSAnders Persson
17703e95bd4aSAnders Persson ent = kmem_zalloc(sizeof (sof_entry_t), KM_SLEEP);
17713e95bd4aSAnders Persson mutex_init(&ent->sofe_lock, NULL, MUTEX_DEFAULT, NULL);
17723e95bd4aSAnders Persson
17733e95bd4aSAnders Persson if ((error = copyinstr(uname, ent->sofe_name, SOF_MAXNAMELEN,
17743e95bd4aSAnders Persson &len)) != 0) {
17753e95bd4aSAnders Persson sof_entry_free(ent);
17763e95bd4aSAnders Persson return (error);
17773e95bd4aSAnders Persson }
17783e95bd4aSAnders Persson
17793e95bd4aSAnders Persson if (get_udatamodel() == DATAMODEL_NATIVE) {
17803e95bd4aSAnders Persson if (copyin(ufilpropp, &filprop, sizeof (filprop)) != 0) {
17813e95bd4aSAnders Persson sof_entry_free(ent);
17823e95bd4aSAnders Persson return (EFAULT);
17833e95bd4aSAnders Persson }
17843e95bd4aSAnders Persson }
17853e95bd4aSAnders Persson #ifdef _SYSCALL32_IMPL
17863e95bd4aSAnders Persson else {
17873e95bd4aSAnders Persson struct sockconfig_filter_props32 filprop32;
17883e95bd4aSAnders Persson
17893e95bd4aSAnders Persson if (copyin(ufilpropp, &filprop32, sizeof (filprop32)) != 0) {
17903e95bd4aSAnders Persson sof_entry_free(ent);
17913e95bd4aSAnders Persson return (EFAULT);
17923e95bd4aSAnders Persson }
17933e95bd4aSAnders Persson filprop.sfp_modname = (char *)(uintptr_t)filprop32.sfp_modname;
17943e95bd4aSAnders Persson filprop.sfp_autoattach = filprop32.sfp_autoattach;
17953e95bd4aSAnders Persson filprop.sfp_hint = filprop32.sfp_hint;
17963e95bd4aSAnders Persson filprop.sfp_hintarg = (char *)(uintptr_t)filprop32.sfp_hintarg;
17973e95bd4aSAnders Persson filprop.sfp_socktuple_cnt = filprop32.sfp_socktuple_cnt;
17983e95bd4aSAnders Persson filprop.sfp_socktuple =
17993e95bd4aSAnders Persson (sof_socktuple_t *)(uintptr_t)filprop32.sfp_socktuple;
18003e95bd4aSAnders Persson }
18013e95bd4aSAnders Persson #endif /* _SYSCALL32_IMPL */
18023e95bd4aSAnders Persson
18033e95bd4aSAnders Persson if ((error = copyinstr(filprop.sfp_modname, ent->sofe_modname,
18043e95bd4aSAnders Persson sizeof (ent->sofe_modname), &len)) != 0) {
18053e95bd4aSAnders Persson sof_entry_free(ent);
18063e95bd4aSAnders Persson return (error);
18073e95bd4aSAnders Persson }
18083e95bd4aSAnders Persson
18093e95bd4aSAnders Persson /*
18103e95bd4aSAnders Persson * A filter must specify at least one socket tuple.
18113e95bd4aSAnders Persson */
18123e95bd4aSAnders Persson if (filprop.sfp_socktuple_cnt == 0 ||
18133e95bd4aSAnders Persson filprop.sfp_socktuple_cnt > SOF_MAXSOCKTUPLECNT) {
18143e95bd4aSAnders Persson sof_entry_free(ent);
18153e95bd4aSAnders Persson return (EINVAL);
18163e95bd4aSAnders Persson }
18173e95bd4aSAnders Persson ent->sofe_flags = filprop.sfp_autoattach ? SOFEF_AUTO : SOFEF_PROG;
18183e95bd4aSAnders Persson ent->sofe_hint = filprop.sfp_hint;
18193e95bd4aSAnders Persson
18203e95bd4aSAnders Persson /*
18213e95bd4aSAnders Persson * Verify the hint, and copy in the hint argument, if necessary.
18223e95bd4aSAnders Persson */
18233e95bd4aSAnders Persson switch (ent->sofe_hint) {
18243e95bd4aSAnders Persson case SOF_HINT_BEFORE:
18253e95bd4aSAnders Persson case SOF_HINT_AFTER:
18263e95bd4aSAnders Persson if ((error = copyinstr(filprop.sfp_hintarg, hintbuf,
18273e95bd4aSAnders Persson sizeof (hintbuf), &len)) != 0) {
18283e95bd4aSAnders Persson sof_entry_free(ent);
18293e95bd4aSAnders Persson return (error);
18303e95bd4aSAnders Persson }
18313e95bd4aSAnders Persson ent->sofe_hintarg = kmem_alloc(len, KM_SLEEP);
18323e95bd4aSAnders Persson bcopy(hintbuf, ent->sofe_hintarg, len);
18333e95bd4aSAnders Persson /* FALLTHRU */
18343e95bd4aSAnders Persson case SOF_HINT_TOP:
18353e95bd4aSAnders Persson case SOF_HINT_BOTTOM:
18363e95bd4aSAnders Persson /* hints cannot be used with programmatic filters */
18373e95bd4aSAnders Persson if (ent->sofe_flags & SOFEF_PROG) {
18383e95bd4aSAnders Persson sof_entry_free(ent);
18393e95bd4aSAnders Persson return (EINVAL);
18403e95bd4aSAnders Persson }
18413e95bd4aSAnders Persson break;
18423e95bd4aSAnders Persson case SOF_HINT_NONE:
18433e95bd4aSAnders Persson break;
18443e95bd4aSAnders Persson default:
18453e95bd4aSAnders Persson /* bad hint value */
18463e95bd4aSAnders Persson sof_entry_free(ent);
18473e95bd4aSAnders Persson return (EINVAL);
18483e95bd4aSAnders Persson }
18493e95bd4aSAnders Persson
18503e95bd4aSAnders Persson ent->sofe_socktuple_cnt = filprop.sfp_socktuple_cnt;
18513e95bd4aSAnders Persson tuplesz = sizeof (sof_socktuple_t) * ent->sofe_socktuple_cnt;
18523e95bd4aSAnders Persson ent->sofe_socktuple = kmem_alloc(tuplesz, KM_SLEEP);
18533e95bd4aSAnders Persson
18543e95bd4aSAnders Persson if (get_udatamodel() == DATAMODEL_NATIVE) {
18553e95bd4aSAnders Persson if (copyin(filprop.sfp_socktuple, ent->sofe_socktuple,
18563e95bd4aSAnders Persson tuplesz)) {
18573e95bd4aSAnders Persson sof_entry_free(ent);
18583e95bd4aSAnders Persson return (EFAULT);
18593e95bd4aSAnders Persson }
18603e95bd4aSAnders Persson }
18613e95bd4aSAnders Persson #ifdef _SYSCALL32_IMPL
18623e95bd4aSAnders Persson else {
18633e95bd4aSAnders Persson int i;
18643e95bd4aSAnders Persson caddr_t data = (caddr_t)filprop.sfp_socktuple;
18653e95bd4aSAnders Persson sof_socktuple_t *tup = ent->sofe_socktuple;
18663e95bd4aSAnders Persson sof_socktuple32_t tup32;
18673e95bd4aSAnders Persson
18683e95bd4aSAnders Persson tup = ent->sofe_socktuple;
18693e95bd4aSAnders Persson for (i = 0; i < ent->sofe_socktuple_cnt; i++, tup++) {
18703e95bd4aSAnders Persson ASSERT(tup < ent->sofe_socktuple + tuplesz);
18713e95bd4aSAnders Persson
18723e95bd4aSAnders Persson if (copyin(data, &tup32, sizeof (tup32)) != 0) {
18733e95bd4aSAnders Persson sof_entry_free(ent);
18743e95bd4aSAnders Persson return (EFAULT);
18750f1702c5SYu Xiangning }
18763e95bd4aSAnders Persson tup->sofst_family = tup32.sofst_family;
18773e95bd4aSAnders Persson tup->sofst_type = tup32.sofst_type;
18783e95bd4aSAnders Persson tup->sofst_protocol = tup32.sofst_protocol;
18793e95bd4aSAnders Persson
18803e95bd4aSAnders Persson data += sizeof (tup32);
18810f1702c5SYu Xiangning }
18823e95bd4aSAnders Persson }
18833e95bd4aSAnders Persson #endif /* _SYSCALL32_IMPL */
18847c478bd9Sstevel@tonic-gate
18853e95bd4aSAnders Persson /* Sockets can start using the filter as soon as the filter is added */
18863e95bd4aSAnders Persson if ((error = sof_entry_add(ent)) != 0)
18873e95bd4aSAnders Persson sof_entry_free(ent);
18883e95bd4aSAnders Persson
18893e95bd4aSAnders Persson return (error);
18903e95bd4aSAnders Persson }
18913e95bd4aSAnders Persson
18923e95bd4aSAnders Persson /*
18933e95bd4aSAnders Persson * Socket configuration system call. It is used to add and remove
18943e95bd4aSAnders Persson * socket types.
18953e95bd4aSAnders Persson */
18963e95bd4aSAnders Persson int
sockconfig(int cmd,void * arg1,void * arg2,void * arg3,void * arg4)18973e95bd4aSAnders Persson sockconfig(int cmd, void *arg1, void *arg2, void *arg3, void *arg4)
18983e95bd4aSAnders Persson {
18993e95bd4aSAnders Persson int error = 0;
19003e95bd4aSAnders Persson
19013e95bd4aSAnders Persson if (secpolicy_net_config(CRED(), B_FALSE) != 0)
19023e95bd4aSAnders Persson return (set_errno(EPERM));
19033e95bd4aSAnders Persson
19043e95bd4aSAnders Persson switch (cmd) {
19053e95bd4aSAnders Persson case SOCKCONFIG_ADD_SOCK:
19063e95bd4aSAnders Persson error = sockconf_add_sock((int)(uintptr_t)arg1,
19073e95bd4aSAnders Persson (int)(uintptr_t)arg2, (int)(uintptr_t)arg3, arg4);
19083e95bd4aSAnders Persson break;
19093e95bd4aSAnders Persson case SOCKCONFIG_REMOVE_SOCK:
19103e95bd4aSAnders Persson error = sockconf_remove_sock((int)(uintptr_t)arg1,
19113e95bd4aSAnders Persson (int)(uintptr_t)arg2, (int)(uintptr_t)arg3);
19123e95bd4aSAnders Persson break;
19133e95bd4aSAnders Persson case SOCKCONFIG_ADD_FILTER:
19143e95bd4aSAnders Persson error = sockconfig_add_filter((const char *)arg1, arg2);
19153e95bd4aSAnders Persson break;
19163e95bd4aSAnders Persson case SOCKCONFIG_REMOVE_FILTER:
19173e95bd4aSAnders Persson error = sockconfig_remove_filter((const char *)arg1);
19183e95bd4aSAnders Persson break;
191919581f84SAlexander Eremin case SOCKCONFIG_GET_SOCKTABLE:
192019581f84SAlexander Eremin error = sockparams_copyout_socktable((int)(uintptr_t)arg1);
192119581f84SAlexander Eremin break;
19223e95bd4aSAnders Persson default:
19233e95bd4aSAnders Persson #ifdef DEBUG
19243e95bd4aSAnders Persson cmn_err(CE_NOTE, "sockconfig: unkonwn subcommand %d", cmd);
19253e95bd4aSAnders Persson #endif
19263e95bd4aSAnders Persson error = EINVAL;
19273e95bd4aSAnders Persson break;
19283e95bd4aSAnders Persson }
19293e95bd4aSAnders Persson
19303e95bd4aSAnders Persson if (error != 0) {
19317c478bd9Sstevel@tonic-gate eprintline(error);
19327c478bd9Sstevel@tonic-gate return (set_errno(error));
19337c478bd9Sstevel@tonic-gate }
19347c478bd9Sstevel@tonic-gate return (0);
19357c478bd9Sstevel@tonic-gate }
19367c478bd9Sstevel@tonic-gate
19377c478bd9Sstevel@tonic-gate
19387c478bd9Sstevel@tonic-gate /*
19397c478bd9Sstevel@tonic-gate * Sendfile is implemented through two schemes, direct I/O or by
19407c478bd9Sstevel@tonic-gate * caching in the filesystem page cache. We cache the input file by
19417c478bd9Sstevel@tonic-gate * default and use direct I/O only if sendfile_max_size is set
19427c478bd9Sstevel@tonic-gate * appropriately as explained below. Note that this logic is consistent
19437c478bd9Sstevel@tonic-gate * with other filesystems where caching is turned on by default
19447c478bd9Sstevel@tonic-gate * unless explicitly turned off by using the DIRECTIO ioctl.
19457c478bd9Sstevel@tonic-gate *
19467c478bd9Sstevel@tonic-gate * We choose a slightly different scheme here. One can turn off
19477c478bd9Sstevel@tonic-gate * caching by setting sendfile_max_size to 0. One can also enable
19487c478bd9Sstevel@tonic-gate * caching of files <= sendfile_max_size by setting sendfile_max_size
19497c478bd9Sstevel@tonic-gate * to an appropriate value. By default sendfile_max_size is set to the
19507c478bd9Sstevel@tonic-gate * maximum value so that all files are cached. In future, we may provide
19517c478bd9Sstevel@tonic-gate * better interfaces for caching the file.
19527c478bd9Sstevel@tonic-gate *
19537c478bd9Sstevel@tonic-gate * Sendfile through Direct I/O (Zero copy)
19547c478bd9Sstevel@tonic-gate * --------------------------------------
19557c478bd9Sstevel@tonic-gate *
19567c478bd9Sstevel@tonic-gate * As disks are normally slower than the network, we can't have a
19577c478bd9Sstevel@tonic-gate * single thread that reads the disk and writes to the network. We
19587c478bd9Sstevel@tonic-gate * need to have parallelism. This is done by having the sendfile
19597c478bd9Sstevel@tonic-gate * thread create another thread that reads from the filesystem
19607c478bd9Sstevel@tonic-gate * and queues it for network processing. In this scheme, the data
19617c478bd9Sstevel@tonic-gate * is never copied anywhere i.e it is zero copy unlike the other
19627c478bd9Sstevel@tonic-gate * scheme.
19637c478bd9Sstevel@tonic-gate *
19647c478bd9Sstevel@tonic-gate * We have a sendfile queue (snfq) where each sendfile
19657c478bd9Sstevel@tonic-gate * request (snf_req_t) is queued for processing by a thread. Number
19667c478bd9Sstevel@tonic-gate * of threads is dynamically allocated and they exit if they are idling
19677c478bd9Sstevel@tonic-gate * beyond a specified amount of time. When each request (snf_req_t) is
19687c478bd9Sstevel@tonic-gate * processed by a thread, it produces a number of mblk_t structures to
19697c478bd9Sstevel@tonic-gate * be consumed by the sendfile thread. snf_deque and snf_enque are
19707c478bd9Sstevel@tonic-gate * used for consuming and producing mblks. Size of the filesystem
1971da6c28aaSamw * read is determined by the tunable (sendfile_read_size). A single
19727c478bd9Sstevel@tonic-gate * mblk holds sendfile_read_size worth of data (except the last
19737c478bd9Sstevel@tonic-gate * read of the file) which is sent down as a whole to the network.
19747c478bd9Sstevel@tonic-gate * sendfile_read_size is set to 1 MB as this seems to be the optimal
19757c478bd9Sstevel@tonic-gate * value for the UFS filesystem backed by a striped storage array.
19767c478bd9Sstevel@tonic-gate *
19777c478bd9Sstevel@tonic-gate * Synchronisation between read (producer) and write (consumer) threads.
19787c478bd9Sstevel@tonic-gate * --------------------------------------------------------------------
19797c478bd9Sstevel@tonic-gate *
19807c478bd9Sstevel@tonic-gate * sr_lock protects sr_ib_head and sr_ib_tail. The lock is held while
19817c478bd9Sstevel@tonic-gate * adding and deleting items in this list. Error can happen anytime
19827c478bd9Sstevel@tonic-gate * during read or write. There could be unprocessed mblks in the
19837c478bd9Sstevel@tonic-gate * sr_ib_XXX list when a read or write error occurs. Whenever error
19847c478bd9Sstevel@tonic-gate * is encountered, we need two things to happen :
19857c478bd9Sstevel@tonic-gate *
19867c478bd9Sstevel@tonic-gate * a) One of the threads need to clean the mblks.
19877c478bd9Sstevel@tonic-gate * b) When one thread encounters an error, the other should stop.
19887c478bd9Sstevel@tonic-gate *
1989da6c28aaSamw * For (a), we don't want to penalize the reader thread as it could do
19907c478bd9Sstevel@tonic-gate * some useful work processing other requests. For (b), the error can
19917c478bd9Sstevel@tonic-gate * be detected by examining sr_read_error or sr_write_error.
19927c478bd9Sstevel@tonic-gate * sr_lock protects sr_read_error and sr_write_error. If both reader and
19937c478bd9Sstevel@tonic-gate * writer encounters error, we need to report the write error back to
19947c478bd9Sstevel@tonic-gate * the application as that's what would have happened if the operations
19957c478bd9Sstevel@tonic-gate * were done sequentially. With this in mind, following should work :
19967c478bd9Sstevel@tonic-gate *
19978cd31312SMarcel Telka * - Check for errors before read or write.
19987c478bd9Sstevel@tonic-gate * - If the reader encounters error, set the error in sr_read_error.
19997c478bd9Sstevel@tonic-gate * Check sr_write_error, if it is set, send cv_signal as it is
20007c478bd9Sstevel@tonic-gate * waiting for reader to complete. If it is not set, the writer
20017c478bd9Sstevel@tonic-gate * is either running sinking data to the network or blocked
20027c478bd9Sstevel@tonic-gate * because of flow control. For handling the latter case, we
20037c478bd9Sstevel@tonic-gate * always send a signal. In any case, it will examine sr_read_error
20047c478bd9Sstevel@tonic-gate * and return. sr_read_error is marked with SR_READ_DONE to tell
20057c478bd9Sstevel@tonic-gate * the writer that the reader is done in all the cases.
20067c478bd9Sstevel@tonic-gate * - If the writer encounters error, set the error in sr_write_error.
20077c478bd9Sstevel@tonic-gate * The reader thread is either blocked because of flow control or
20087c478bd9Sstevel@tonic-gate * running reading data from the disk. For the former, we need to
20097c478bd9Sstevel@tonic-gate * wakeup the thread. Again to keep it simple, we always wake up
20107c478bd9Sstevel@tonic-gate * the reader thread. Then, wait for the read thread to complete
20117c478bd9Sstevel@tonic-gate * if it is not done yet. Cleanup and return.
20127c478bd9Sstevel@tonic-gate *
20137c478bd9Sstevel@tonic-gate * High and low water marks for the read thread.
20147c478bd9Sstevel@tonic-gate * --------------------------------------------
20157c478bd9Sstevel@tonic-gate *
20167c478bd9Sstevel@tonic-gate * If sendfile() is used to send data over a slow network, we need to
20177c478bd9Sstevel@tonic-gate * make sure that the read thread does not produce data at a faster
20187c478bd9Sstevel@tonic-gate * rate than the network. This can happen if the disk is faster than
20197c478bd9Sstevel@tonic-gate * the network. In such a case, we don't want to build a very large queue.
20207c478bd9Sstevel@tonic-gate * But we would still like to get all of the network throughput possible.
20217c478bd9Sstevel@tonic-gate * This implies that network should never block waiting for data.
20227c478bd9Sstevel@tonic-gate * As there are lot of disk throughput/network throughput combinations
20237c478bd9Sstevel@tonic-gate * possible, it is difficult to come up with an accurate number.
20247c478bd9Sstevel@tonic-gate * A typical 10K RPM disk has a max seek latency 17ms and rotational
20257c478bd9Sstevel@tonic-gate * latency of 3ms for reading a disk block. Thus, the total latency to
20267c478bd9Sstevel@tonic-gate * initiate a new read, transfer data from the disk and queue for
20277c478bd9Sstevel@tonic-gate * transmission would take about a max of 25ms. Todays max transfer rate
20287c478bd9Sstevel@tonic-gate * for network is 100MB/sec. If the thread is blocked because of flow
20297c478bd9Sstevel@tonic-gate * control, it would take 25ms to get new data ready for transmission.
20307c478bd9Sstevel@tonic-gate * We have to make sure that network is not idling, while we are initiating
20317c478bd9Sstevel@tonic-gate * new transfers. So, at 100MB/sec, to keep network busy we would need
2032da6c28aaSamw * 2.5MB of data. Rounding off, we keep the low water mark to be 3MB of data.
20337c478bd9Sstevel@tonic-gate * We need to pick a high water mark so that the woken up thread would
20347c478bd9Sstevel@tonic-gate * do considerable work before blocking again to prevent thrashing. Currently,
20357c478bd9Sstevel@tonic-gate * we pick this to be 10 times that of the low water mark.
20367c478bd9Sstevel@tonic-gate *
20377c478bd9Sstevel@tonic-gate * Sendfile with segmap caching (One copy from page cache to mblks).
20387c478bd9Sstevel@tonic-gate * ----------------------------------------------------------------
20397c478bd9Sstevel@tonic-gate *
20407c478bd9Sstevel@tonic-gate * We use the segmap cache for caching the file, if the size of file
20417c478bd9Sstevel@tonic-gate * is <= sendfile_max_size. In this case we don't use threads as VM
20427c478bd9Sstevel@tonic-gate * is reasonably fast enough to keep up with the network. If the underlying
20437c478bd9Sstevel@tonic-gate * transport allows, we call segmap_getmapflt() to map MAXBSIZE (8K) worth
20447c478bd9Sstevel@tonic-gate * of data into segmap space, and use the virtual address from segmap
20457c478bd9Sstevel@tonic-gate * directly through desballoc() to avoid copy. Once the transport is done
20467c478bd9Sstevel@tonic-gate * with the data, the mapping will be released through segmap_release()
20477c478bd9Sstevel@tonic-gate * called by the call-back routine.
20487c478bd9Sstevel@tonic-gate *
20497c478bd9Sstevel@tonic-gate * If zero-copy is not allowed by the transport, we simply call VOP_READ()
20507c478bd9Sstevel@tonic-gate * to copy the data from the filesystem into our temporary network buffer.
20517c478bd9Sstevel@tonic-gate *
20527c478bd9Sstevel@tonic-gate * To disable caching, set sendfile_max_size to 0.
20537c478bd9Sstevel@tonic-gate */
20547c478bd9Sstevel@tonic-gate
20557c478bd9Sstevel@tonic-gate uint_t sendfile_read_size = 1024 * 1024;
20567c478bd9Sstevel@tonic-gate #define SENDFILE_REQ_LOWAT 3 * 1024 * 1024
20577c478bd9Sstevel@tonic-gate uint_t sendfile_req_lowat = SENDFILE_REQ_LOWAT;
20587c478bd9Sstevel@tonic-gate uint_t sendfile_req_hiwat = 10 * SENDFILE_REQ_LOWAT;
20597c478bd9Sstevel@tonic-gate struct sendfile_stats sf_stats;
20607c478bd9Sstevel@tonic-gate struct sendfile_queue *snfq;
20617c478bd9Sstevel@tonic-gate clock_t snfq_timeout;
20627c478bd9Sstevel@tonic-gate off64_t sendfile_max_size;
20637c478bd9Sstevel@tonic-gate
20647c478bd9Sstevel@tonic-gate static void snf_enque(snf_req_t *, mblk_t *);
20657c478bd9Sstevel@tonic-gate static mblk_t *snf_deque(snf_req_t *);
20667c478bd9Sstevel@tonic-gate
20677c478bd9Sstevel@tonic-gate void
sendfile_init(void)20687c478bd9Sstevel@tonic-gate sendfile_init(void)
20697c478bd9Sstevel@tonic-gate {
20707c478bd9Sstevel@tonic-gate snfq = kmem_zalloc(sizeof (struct sendfile_queue), KM_SLEEP);
20717c478bd9Sstevel@tonic-gate
20727c478bd9Sstevel@tonic-gate mutex_init(&snfq->snfq_lock, NULL, MUTEX_DEFAULT, NULL);
20737c478bd9Sstevel@tonic-gate cv_init(&snfq->snfq_cv, NULL, CV_DEFAULT, NULL);
20747c478bd9Sstevel@tonic-gate snfq->snfq_max_threads = max_ncpus;
20757c478bd9Sstevel@tonic-gate snfq_timeout = SNFQ_TIMEOUT;
20767c478bd9Sstevel@tonic-gate /* Cache all files by default. */
20777c478bd9Sstevel@tonic-gate sendfile_max_size = MAXOFFSET_T;
20787c478bd9Sstevel@tonic-gate }
20797c478bd9Sstevel@tonic-gate
20807c478bd9Sstevel@tonic-gate /*
20817c478bd9Sstevel@tonic-gate * Queues a mblk_t for network processing.
20827c478bd9Sstevel@tonic-gate */
20837c478bd9Sstevel@tonic-gate static void
snf_enque(snf_req_t * sr,mblk_t * mp)20847c478bd9Sstevel@tonic-gate snf_enque(snf_req_t *sr, mblk_t *mp)
20857c478bd9Sstevel@tonic-gate {
20867c478bd9Sstevel@tonic-gate mp->b_next = NULL;
20877c478bd9Sstevel@tonic-gate mutex_enter(&sr->sr_lock);
20887c478bd9Sstevel@tonic-gate if (sr->sr_mp_head == NULL) {
20897c478bd9Sstevel@tonic-gate sr->sr_mp_head = sr->sr_mp_tail = mp;
20907c478bd9Sstevel@tonic-gate cv_signal(&sr->sr_cv);
20917c478bd9Sstevel@tonic-gate } else {
20927c478bd9Sstevel@tonic-gate sr->sr_mp_tail->b_next = mp;
20937c478bd9Sstevel@tonic-gate sr->sr_mp_tail = mp;
20947c478bd9Sstevel@tonic-gate }
20957c478bd9Sstevel@tonic-gate sr->sr_qlen += MBLKL(mp);
20967c478bd9Sstevel@tonic-gate while ((sr->sr_qlen > sr->sr_hiwat) &&
20977c478bd9Sstevel@tonic-gate (sr->sr_write_error == 0)) {
20987c478bd9Sstevel@tonic-gate sf_stats.ss_full_waits++;
20997c478bd9Sstevel@tonic-gate cv_wait(&sr->sr_cv, &sr->sr_lock);
21007c478bd9Sstevel@tonic-gate }
21017c478bd9Sstevel@tonic-gate mutex_exit(&sr->sr_lock);
21027c478bd9Sstevel@tonic-gate }
21037c478bd9Sstevel@tonic-gate
21047c478bd9Sstevel@tonic-gate /*
21057c478bd9Sstevel@tonic-gate * De-queues a mblk_t for network processing.
21067c478bd9Sstevel@tonic-gate */
21077c478bd9Sstevel@tonic-gate static mblk_t *
snf_deque(snf_req_t * sr)21087c478bd9Sstevel@tonic-gate snf_deque(snf_req_t *sr)
21097c478bd9Sstevel@tonic-gate {
21107c478bd9Sstevel@tonic-gate mblk_t *mp;
21117c478bd9Sstevel@tonic-gate
21127c478bd9Sstevel@tonic-gate mutex_enter(&sr->sr_lock);
21137c478bd9Sstevel@tonic-gate /*
21147c478bd9Sstevel@tonic-gate * If we have encountered an error on read or read is
21157c478bd9Sstevel@tonic-gate * completed and no more mblks, return NULL.
21167c478bd9Sstevel@tonic-gate * We need to check for NULL sr_mp_head also as
21177c478bd9Sstevel@tonic-gate * the reads could have completed and there is
21187c478bd9Sstevel@tonic-gate * nothing more to come.
21197c478bd9Sstevel@tonic-gate */
21207c478bd9Sstevel@tonic-gate if (((sr->sr_read_error & ~SR_READ_DONE) != 0) ||
21217c478bd9Sstevel@tonic-gate ((sr->sr_read_error & SR_READ_DONE) &&
21227c478bd9Sstevel@tonic-gate sr->sr_mp_head == NULL)) {
21237c478bd9Sstevel@tonic-gate mutex_exit(&sr->sr_lock);
21247c478bd9Sstevel@tonic-gate return (NULL);
21257c478bd9Sstevel@tonic-gate }
21267c478bd9Sstevel@tonic-gate /*
21277c478bd9Sstevel@tonic-gate * To start with neither SR_READ_DONE is marked nor
21287c478bd9Sstevel@tonic-gate * the error is set. When we wake up from cv_wait,
21297c478bd9Sstevel@tonic-gate * following are the possibilities :
21307c478bd9Sstevel@tonic-gate *
21317c478bd9Sstevel@tonic-gate * a) sr_read_error is zero and mblks are queued.
21327c478bd9Sstevel@tonic-gate * b) sr_read_error is set to SR_READ_DONE
21337c478bd9Sstevel@tonic-gate * and mblks are queued.
21347c478bd9Sstevel@tonic-gate * c) sr_read_error is set to SR_READ_DONE
21357c478bd9Sstevel@tonic-gate * and no mblks.
21367c478bd9Sstevel@tonic-gate * d) sr_read_error is set to some error other
21377c478bd9Sstevel@tonic-gate * than SR_READ_DONE.
21387c478bd9Sstevel@tonic-gate */
21397c478bd9Sstevel@tonic-gate
21407c478bd9Sstevel@tonic-gate while ((sr->sr_read_error == 0) && (sr->sr_mp_head == NULL)) {
21417c478bd9Sstevel@tonic-gate sf_stats.ss_empty_waits++;
21427c478bd9Sstevel@tonic-gate cv_wait(&sr->sr_cv, &sr->sr_lock);
21437c478bd9Sstevel@tonic-gate }
21447c478bd9Sstevel@tonic-gate /* Handle (a) and (b) first - the normal case. */
21457c478bd9Sstevel@tonic-gate if (((sr->sr_read_error & ~SR_READ_DONE) == 0) &&
21467c478bd9Sstevel@tonic-gate (sr->sr_mp_head != NULL)) {
21477c478bd9Sstevel@tonic-gate mp = sr->sr_mp_head;
21487c478bd9Sstevel@tonic-gate sr->sr_mp_head = mp->b_next;
21497c478bd9Sstevel@tonic-gate sr->sr_qlen -= MBLKL(mp);
21507c478bd9Sstevel@tonic-gate if (sr->sr_qlen < sr->sr_lowat)
21517c478bd9Sstevel@tonic-gate cv_signal(&sr->sr_cv);
21527c478bd9Sstevel@tonic-gate mutex_exit(&sr->sr_lock);
21537c478bd9Sstevel@tonic-gate mp->b_next = NULL;
21547c478bd9Sstevel@tonic-gate return (mp);
21557c478bd9Sstevel@tonic-gate }
21567c478bd9Sstevel@tonic-gate /* Handle (c) and (d). */
21577c478bd9Sstevel@tonic-gate mutex_exit(&sr->sr_lock);
21587c478bd9Sstevel@tonic-gate return (NULL);
21597c478bd9Sstevel@tonic-gate }
21607c478bd9Sstevel@tonic-gate
21617c478bd9Sstevel@tonic-gate /*
21627c478bd9Sstevel@tonic-gate * Reads data from the filesystem and queues it for network processing.
21637c478bd9Sstevel@tonic-gate */
21647c478bd9Sstevel@tonic-gate void
snf_async_read(snf_req_t * sr)21657c478bd9Sstevel@tonic-gate snf_async_read(snf_req_t *sr)
21667c478bd9Sstevel@tonic-gate {
21677c478bd9Sstevel@tonic-gate size_t iosize;
21687c478bd9Sstevel@tonic-gate u_offset_t fileoff;
21697c478bd9Sstevel@tonic-gate u_offset_t size;
21707c478bd9Sstevel@tonic-gate int ret_size;
21717c478bd9Sstevel@tonic-gate int error;
21727c478bd9Sstevel@tonic-gate file_t *fp;
21737c478bd9Sstevel@tonic-gate mblk_t *mp;
2174b273e065Skrishna struct vnode *vp;
2175b273e065Skrishna int extra = 0;
2176e116a42fSPrakash Jalan int maxblk = 0;
2177e116a42fSPrakash Jalan int wroff = 0;
2178e116a42fSPrakash Jalan struct sonode *so;
21797c478bd9Sstevel@tonic-gate
21807c478bd9Sstevel@tonic-gate fp = sr->sr_fp;
21817c478bd9Sstevel@tonic-gate size = sr->sr_file_size;
21827c478bd9Sstevel@tonic-gate fileoff = sr->sr_file_off;
21837c478bd9Sstevel@tonic-gate
21847c478bd9Sstevel@tonic-gate /*
21857c478bd9Sstevel@tonic-gate * Ignore the error for filesystems that doesn't support DIRECTIO.
21867c478bd9Sstevel@tonic-gate */
21877c478bd9Sstevel@tonic-gate (void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_ON, 0,
2188da6c28aaSamw kcred, NULL, NULL);
21897c478bd9Sstevel@tonic-gate
2190e116a42fSPrakash Jalan vp = sr->sr_vp;
2191b273e065Skrishna if (vp->v_type == VSOCK) {
2192b273e065Skrishna stdata_t *stp;
2193b273e065Skrishna
2194b273e065Skrishna /*
2195b273e065Skrishna * Get the extra space to insert a header and a trailer.
2196b273e065Skrishna */
2197e116a42fSPrakash Jalan so = VTOSO(vp);
2198b273e065Skrishna stp = vp->v_stream;
21990f1702c5SYu Xiangning if (stp == NULL) {
22000f1702c5SYu Xiangning wroff = so->so_proto_props.sopp_wroff;
22010f1702c5SYu Xiangning maxblk = so->so_proto_props.sopp_maxblk;
22020f1702c5SYu Xiangning extra = wroff + so->so_proto_props.sopp_tail;
22030f1702c5SYu Xiangning } else {
22040f1702c5SYu Xiangning wroff = (int)(stp->sd_wroff);
22050f1702c5SYu Xiangning maxblk = (int)(stp->sd_maxblk);
22060f1702c5SYu Xiangning extra = wroff + (int)(stp->sd_tail);
22070f1702c5SYu Xiangning }
2208b273e065Skrishna }
2209b273e065Skrishna
22107c478bd9Sstevel@tonic-gate while ((size != 0) && (sr->sr_write_error == 0)) {
22117c478bd9Sstevel@tonic-gate
22127c478bd9Sstevel@tonic-gate iosize = (int)MIN(sr->sr_maxpsz, size);
22137c478bd9Sstevel@tonic-gate
2214e116a42fSPrakash Jalan /*
22153e95bd4aSAnders Persson * Socket filters can limit the mblk size,
22163e95bd4aSAnders Persson * so limit reads to maxblk if there are
22173e95bd4aSAnders Persson * filters present.
2218e116a42fSPrakash Jalan */
22193e95bd4aSAnders Persson if (vp->v_type == VSOCK &&
2220dd49f125SAnders Persson so->so_filter_active > 0 && maxblk != INFPSZ)
2221e116a42fSPrakash Jalan iosize = (int)MIN(iosize, maxblk);
2222e116a42fSPrakash Jalan
2223de8c4a14SErik Nordmark if (is_system_labeled()) {
2224de8c4a14SErik Nordmark mp = allocb_cred(iosize + extra, CRED(),
2225de8c4a14SErik Nordmark curproc->p_pid);
2226de8c4a14SErik Nordmark } else {
2227de8c4a14SErik Nordmark mp = allocb(iosize + extra, BPRI_MED);
2228de8c4a14SErik Nordmark }
2229de8c4a14SErik Nordmark if (mp == NULL) {
22307c478bd9Sstevel@tonic-gate error = EAGAIN;
22317c478bd9Sstevel@tonic-gate break;
22327c478bd9Sstevel@tonic-gate }
2233e116a42fSPrakash Jalan
2234e116a42fSPrakash Jalan mp->b_rptr += wroff;
2235e116a42fSPrakash Jalan
22367c478bd9Sstevel@tonic-gate ret_size = soreadfile(fp, mp->b_rptr, fileoff, &error, iosize);
22377c478bd9Sstevel@tonic-gate
22387c478bd9Sstevel@tonic-gate /* Error or Reached EOF ? */
22397c478bd9Sstevel@tonic-gate if ((error != 0) || (ret_size == 0)) {
22407c478bd9Sstevel@tonic-gate freeb(mp);
22417c478bd9Sstevel@tonic-gate break;
22427c478bd9Sstevel@tonic-gate }
22437c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + ret_size;
22447c478bd9Sstevel@tonic-gate
22457c478bd9Sstevel@tonic-gate snf_enque(sr, mp);
22467c478bd9Sstevel@tonic-gate size -= ret_size;
22477c478bd9Sstevel@tonic-gate fileoff += ret_size;
22487c478bd9Sstevel@tonic-gate }
22497c478bd9Sstevel@tonic-gate (void) VOP_IOCTL(fp->f_vnode, _FIODIRECTIO, DIRECTIO_OFF, 0,
2250da6c28aaSamw kcred, NULL, NULL);
22517c478bd9Sstevel@tonic-gate mutex_enter(&sr->sr_lock);
22527c478bd9Sstevel@tonic-gate sr->sr_read_error = error;
22537c478bd9Sstevel@tonic-gate sr->sr_read_error |= SR_READ_DONE;
22547c478bd9Sstevel@tonic-gate cv_signal(&sr->sr_cv);
22557c478bd9Sstevel@tonic-gate mutex_exit(&sr->sr_lock);
22567c478bd9Sstevel@tonic-gate }
22577c478bd9Sstevel@tonic-gate
22587c478bd9Sstevel@tonic-gate void
snf_async_thread(void)22597c478bd9Sstevel@tonic-gate snf_async_thread(void)
22607c478bd9Sstevel@tonic-gate {
22617c478bd9Sstevel@tonic-gate snf_req_t *sr;
22627c478bd9Sstevel@tonic-gate callb_cpr_t cprinfo;
22637c478bd9Sstevel@tonic-gate clock_t time_left = 1;
22647c478bd9Sstevel@tonic-gate
22657c478bd9Sstevel@tonic-gate CALLB_CPR_INIT(&cprinfo, &snfq->snfq_lock, callb_generic_cpr, "snfq");
22667c478bd9Sstevel@tonic-gate
22677c478bd9Sstevel@tonic-gate mutex_enter(&snfq->snfq_lock);
22687c478bd9Sstevel@tonic-gate for (;;) {
22697c478bd9Sstevel@tonic-gate /*
22707c478bd9Sstevel@tonic-gate * If we didn't find a entry, then block until woken up
22717c478bd9Sstevel@tonic-gate * again and then look through the queues again.
22727c478bd9Sstevel@tonic-gate */
22737c478bd9Sstevel@tonic-gate while ((sr = snfq->snfq_req_head) == NULL) {
22747c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_BEGIN(&cprinfo);
22757c478bd9Sstevel@tonic-gate if (time_left <= 0) {
22767c478bd9Sstevel@tonic-gate snfq->snfq_svc_threads--;
22777c478bd9Sstevel@tonic-gate CALLB_CPR_EXIT(&cprinfo);
22787c478bd9Sstevel@tonic-gate thread_exit();
22797c478bd9Sstevel@tonic-gate /* NOTREACHED */
22807c478bd9Sstevel@tonic-gate }
22817c478bd9Sstevel@tonic-gate snfq->snfq_idle_cnt++;
22827c478bd9Sstevel@tonic-gate
2283d3d50737SRafael Vanoni time_left = cv_reltimedwait(&snfq->snfq_cv,
2284d3d50737SRafael Vanoni &snfq->snfq_lock, snfq_timeout, TR_CLOCK_TICK);
22857c478bd9Sstevel@tonic-gate snfq->snfq_idle_cnt--;
22867c478bd9Sstevel@tonic-gate
22877c478bd9Sstevel@tonic-gate CALLB_CPR_SAFE_END(&cprinfo, &snfq->snfq_lock);
22887c478bd9Sstevel@tonic-gate }
22897c478bd9Sstevel@tonic-gate snfq->snfq_req_head = sr->sr_next;
22907c478bd9Sstevel@tonic-gate snfq->snfq_req_cnt--;
22917c478bd9Sstevel@tonic-gate mutex_exit(&snfq->snfq_lock);
22927c478bd9Sstevel@tonic-gate snf_async_read(sr);
22937c478bd9Sstevel@tonic-gate mutex_enter(&snfq->snfq_lock);
22947c478bd9Sstevel@tonic-gate }
22957c478bd9Sstevel@tonic-gate }
22967c478bd9Sstevel@tonic-gate
22977c478bd9Sstevel@tonic-gate
22987c478bd9Sstevel@tonic-gate snf_req_t *
create_thread(int operation,struct vnode * vp,file_t * fp,u_offset_t fileoff,u_offset_t size)22997c478bd9Sstevel@tonic-gate create_thread(int operation, struct vnode *vp, file_t *fp,
23007c478bd9Sstevel@tonic-gate u_offset_t fileoff, u_offset_t size)
23017c478bd9Sstevel@tonic-gate {
23027c478bd9Sstevel@tonic-gate snf_req_t *sr;
23037c478bd9Sstevel@tonic-gate stdata_t *stp;
23047c478bd9Sstevel@tonic-gate
23057c478bd9Sstevel@tonic-gate sr = (snf_req_t *)kmem_zalloc(sizeof (snf_req_t), KM_SLEEP);
23067c478bd9Sstevel@tonic-gate
23077c478bd9Sstevel@tonic-gate sr->sr_vp = vp;
23087c478bd9Sstevel@tonic-gate sr->sr_fp = fp;
23097c478bd9Sstevel@tonic-gate stp = vp->v_stream;
23107c478bd9Sstevel@tonic-gate
23117c478bd9Sstevel@tonic-gate /*
23127c478bd9Sstevel@tonic-gate * store sd_qn_maxpsz into sr_maxpsz while we have stream head.
23137c478bd9Sstevel@tonic-gate * stream might be closed before thread returns from snf_async_read.
23147c478bd9Sstevel@tonic-gate */
23150f1702c5SYu Xiangning if (stp != NULL && stp->sd_qn_maxpsz > 0) {
23167c478bd9Sstevel@tonic-gate sr->sr_maxpsz = MIN(MAXBSIZE, stp->sd_qn_maxpsz);
23177c478bd9Sstevel@tonic-gate } else {
23187c478bd9Sstevel@tonic-gate sr->sr_maxpsz = MAXBSIZE;
23197c478bd9Sstevel@tonic-gate }
23207c478bd9Sstevel@tonic-gate
23217c478bd9Sstevel@tonic-gate sr->sr_operation = operation;
23227c478bd9Sstevel@tonic-gate sr->sr_file_off = fileoff;
23237c478bd9Sstevel@tonic-gate sr->sr_file_size = size;
23247c478bd9Sstevel@tonic-gate sr->sr_hiwat = sendfile_req_hiwat;
23257c478bd9Sstevel@tonic-gate sr->sr_lowat = sendfile_req_lowat;
23267c478bd9Sstevel@tonic-gate mutex_init(&sr->sr_lock, NULL, MUTEX_DEFAULT, NULL);
23277c478bd9Sstevel@tonic-gate cv_init(&sr->sr_cv, NULL, CV_DEFAULT, NULL);
23287c478bd9Sstevel@tonic-gate /*
23297c478bd9Sstevel@tonic-gate * See whether we need another thread for servicing this
23307c478bd9Sstevel@tonic-gate * request. If there are already enough requests queued
23317c478bd9Sstevel@tonic-gate * for the threads, create one if not exceeding
23327c478bd9Sstevel@tonic-gate * snfq_max_threads.
23337c478bd9Sstevel@tonic-gate */
23347c478bd9Sstevel@tonic-gate mutex_enter(&snfq->snfq_lock);
23357c478bd9Sstevel@tonic-gate if (snfq->snfq_req_cnt >= snfq->snfq_idle_cnt &&
23367c478bd9Sstevel@tonic-gate snfq->snfq_svc_threads < snfq->snfq_max_threads) {
23377c478bd9Sstevel@tonic-gate (void) thread_create(NULL, 0, &snf_async_thread, 0, 0, &p0,
23387c478bd9Sstevel@tonic-gate TS_RUN, minclsyspri);
23397c478bd9Sstevel@tonic-gate snfq->snfq_svc_threads++;
23407c478bd9Sstevel@tonic-gate }
23417c478bd9Sstevel@tonic-gate if (snfq->snfq_req_head == NULL) {
23427c478bd9Sstevel@tonic-gate snfq->snfq_req_head = snfq->snfq_req_tail = sr;
23437c478bd9Sstevel@tonic-gate cv_signal(&snfq->snfq_cv);
23447c478bd9Sstevel@tonic-gate } else {
23457c478bd9Sstevel@tonic-gate snfq->snfq_req_tail->sr_next = sr;
23467c478bd9Sstevel@tonic-gate snfq->snfq_req_tail = sr;
23477c478bd9Sstevel@tonic-gate }
23487c478bd9Sstevel@tonic-gate snfq->snfq_req_cnt++;
23497c478bd9Sstevel@tonic-gate mutex_exit(&snfq->snfq_lock);
23507c478bd9Sstevel@tonic-gate return (sr);
23517c478bd9Sstevel@tonic-gate }
23527c478bd9Sstevel@tonic-gate
23537c478bd9Sstevel@tonic-gate int
snf_direct_io(file_t * fp,file_t * rfp,u_offset_t fileoff,u_offset_t size,ssize_t * count)23547c478bd9Sstevel@tonic-gate snf_direct_io(file_t *fp, file_t *rfp, u_offset_t fileoff, u_offset_t size,
23557c478bd9Sstevel@tonic-gate ssize_t *count)
23567c478bd9Sstevel@tonic-gate {
23577c478bd9Sstevel@tonic-gate snf_req_t *sr;
23587c478bd9Sstevel@tonic-gate mblk_t *mp;
23597c478bd9Sstevel@tonic-gate int iosize;
23607c478bd9Sstevel@tonic-gate int error = 0;
23617c478bd9Sstevel@tonic-gate short fflag;
23627c478bd9Sstevel@tonic-gate struct vnode *vp;
23637c478bd9Sstevel@tonic-gate int ksize;
23640f1702c5SYu Xiangning struct nmsghdr msg;
23657c478bd9Sstevel@tonic-gate
23667c478bd9Sstevel@tonic-gate ksize = 0;
23677c478bd9Sstevel@tonic-gate *count = 0;
23680f1702c5SYu Xiangning bzero(&msg, sizeof (msg));
23697c478bd9Sstevel@tonic-gate
23707c478bd9Sstevel@tonic-gate vp = fp->f_vnode;
23717c478bd9Sstevel@tonic-gate fflag = fp->f_flag;
23727c478bd9Sstevel@tonic-gate if ((sr = create_thread(READ_OP, vp, rfp, fileoff, size)) == NULL)
23737c478bd9Sstevel@tonic-gate return (EAGAIN);
23747c478bd9Sstevel@tonic-gate
23757c478bd9Sstevel@tonic-gate /*
23767c478bd9Sstevel@tonic-gate * We check for read error in snf_deque. It has to check
23777c478bd9Sstevel@tonic-gate * for successful READ_DONE and return NULL, and we might
23787c478bd9Sstevel@tonic-gate * as well make an additional check there.
23797c478bd9Sstevel@tonic-gate */
23807c478bd9Sstevel@tonic-gate while ((mp = snf_deque(sr)) != NULL) {
23817c478bd9Sstevel@tonic-gate
23827c478bd9Sstevel@tonic-gate if (ISSIG(curthread, JUSTLOOKING)) {
23837c478bd9Sstevel@tonic-gate freeb(mp);
23847c478bd9Sstevel@tonic-gate error = EINTR;
23857c478bd9Sstevel@tonic-gate break;
23867c478bd9Sstevel@tonic-gate }
23877c478bd9Sstevel@tonic-gate iosize = MBLKL(mp);
23887c478bd9Sstevel@tonic-gate
23890f1702c5SYu Xiangning error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp);
23900f1702c5SYu Xiangning
23910f1702c5SYu Xiangning if (error != 0) {
23920f1702c5SYu Xiangning if (mp != NULL)
23930f1702c5SYu Xiangning freeb(mp);
23947c478bd9Sstevel@tonic-gate break;
23957c478bd9Sstevel@tonic-gate }
23967c478bd9Sstevel@tonic-gate ksize += iosize;
23977c478bd9Sstevel@tonic-gate }
23987c478bd9Sstevel@tonic-gate *count = ksize;
23997c478bd9Sstevel@tonic-gate
24007c478bd9Sstevel@tonic-gate mutex_enter(&sr->sr_lock);
24017c478bd9Sstevel@tonic-gate sr->sr_write_error = error;
24027c478bd9Sstevel@tonic-gate /* Look at the big comments on why we cv_signal here. */
24037c478bd9Sstevel@tonic-gate cv_signal(&sr->sr_cv);
24047c478bd9Sstevel@tonic-gate
24057c478bd9Sstevel@tonic-gate /* Wait for the reader to complete always. */
24067c478bd9Sstevel@tonic-gate while (!(sr->sr_read_error & SR_READ_DONE)) {
24077c478bd9Sstevel@tonic-gate cv_wait(&sr->sr_cv, &sr->sr_lock);
24087c478bd9Sstevel@tonic-gate }
24097c478bd9Sstevel@tonic-gate /* If there is no write error, check for read error. */
24107c478bd9Sstevel@tonic-gate if (error == 0)
24117c478bd9Sstevel@tonic-gate error = (sr->sr_read_error & ~SR_READ_DONE);
24127c478bd9Sstevel@tonic-gate
24137c478bd9Sstevel@tonic-gate if (error != 0) {
24147c478bd9Sstevel@tonic-gate mblk_t *next_mp;
24157c478bd9Sstevel@tonic-gate
24167c478bd9Sstevel@tonic-gate mp = sr->sr_mp_head;
24177c478bd9Sstevel@tonic-gate while (mp != NULL) {
24187c478bd9Sstevel@tonic-gate next_mp = mp->b_next;
24197c478bd9Sstevel@tonic-gate mp->b_next = NULL;
24207c478bd9Sstevel@tonic-gate freeb(mp);
24217c478bd9Sstevel@tonic-gate mp = next_mp;
24227c478bd9Sstevel@tonic-gate }
24237c478bd9Sstevel@tonic-gate }
24247c478bd9Sstevel@tonic-gate mutex_exit(&sr->sr_lock);
24257c478bd9Sstevel@tonic-gate kmem_free(sr, sizeof (snf_req_t));
24267c478bd9Sstevel@tonic-gate return (error);
24277c478bd9Sstevel@tonic-gate }
24287c478bd9Sstevel@tonic-gate
2429ead83321SVasumathi Sundaram - Sun Microsystems /* Maximum no.of pages allocated by vpm for sendfile at a time */
243031c2c73cSVasumathi Sundaram - Sun Microsystems #define SNF_VPMMAXPGS (VPMMAXPGS/2)
2431ead83321SVasumathi Sundaram - Sun Microsystems
2432ead83321SVasumathi Sundaram - Sun Microsystems /*
2433ead83321SVasumathi Sundaram - Sun Microsystems * Maximum no.of elements in the list returned by vpm, including
2434ead83321SVasumathi Sundaram - Sun Microsystems * NULL for the last entry
2435ead83321SVasumathi Sundaram - Sun Microsystems */
243631c2c73cSVasumathi Sundaram - Sun Microsystems #define SNF_MAXVMAPS (SNF_VPMMAXPGS + 1)
243731c2c73cSVasumathi Sundaram - Sun Microsystems
243831c2c73cSVasumathi Sundaram - Sun Microsystems typedef struct {
2439ead83321SVasumathi Sundaram - Sun Microsystems unsigned int snfv_ref;
2440ead83321SVasumathi Sundaram - Sun Microsystems frtn_t snfv_frtn;
2441ead83321SVasumathi Sundaram - Sun Microsystems vnode_t *snfv_vp;
2442ead83321SVasumathi Sundaram - Sun Microsystems struct vmap snfv_vml[SNF_MAXVMAPS];
244331c2c73cSVasumathi Sundaram - Sun Microsystems } snf_vmap_desbinfo;
244431c2c73cSVasumathi Sundaram - Sun Microsystems
24457c478bd9Sstevel@tonic-gate typedef struct {
24467c478bd9Sstevel@tonic-gate frtn_t snfi_frtn;
24477c478bd9Sstevel@tonic-gate caddr_t snfi_base;
24487c478bd9Sstevel@tonic-gate uint_t snfi_mapoff;
24497c478bd9Sstevel@tonic-gate size_t snfi_len;
24507c478bd9Sstevel@tonic-gate vnode_t *snfi_vp;
24517c478bd9Sstevel@tonic-gate } snf_smap_desbinfo;
24527c478bd9Sstevel@tonic-gate
2453ead83321SVasumathi Sundaram - Sun Microsystems /*
2454ead83321SVasumathi Sundaram - Sun Microsystems * The callback function used for vpm mapped mblks called when the last ref of
2455ead83321SVasumathi Sundaram - Sun Microsystems * the mblk is dropped which normally occurs when TCP receives the ack. But it
2456ead83321SVasumathi Sundaram - Sun Microsystems * can be the driver too due to lazy reclaim.
2457ead83321SVasumathi Sundaram - Sun Microsystems */
245831c2c73cSVasumathi Sundaram - Sun Microsystems void
snf_vmap_desbfree(snf_vmap_desbinfo * snfv)245931c2c73cSVasumathi Sundaram - Sun Microsystems snf_vmap_desbfree(snf_vmap_desbinfo *snfv)
246031c2c73cSVasumathi Sundaram - Sun Microsystems {
2461ead83321SVasumathi Sundaram - Sun Microsystems ASSERT(snfv->snfv_ref != 0);
24621a5e258fSJosef 'Jeff' Sipek if (atomic_dec_32_nv(&snfv->snfv_ref) == 0) {
2463ead83321SVasumathi Sundaram - Sun Microsystems vpm_unmap_pages(snfv->snfv_vml, S_READ);
246431c2c73cSVasumathi Sundaram - Sun Microsystems VN_RELE(snfv->snfv_vp);
246531c2c73cSVasumathi Sundaram - Sun Microsystems kmem_free(snfv, sizeof (snf_vmap_desbinfo));
246631c2c73cSVasumathi Sundaram - Sun Microsystems }
246731c2c73cSVasumathi Sundaram - Sun Microsystems }
246831c2c73cSVasumathi Sundaram - Sun Microsystems
24697c478bd9Sstevel@tonic-gate /*
2470ead83321SVasumathi Sundaram - Sun Microsystems * The callback function used for segmap'ped mblks called when the last ref of
2471ead83321SVasumathi Sundaram - Sun Microsystems * the mblk is dropped which normally occurs when TCP receives the ack. But it
2472ead83321SVasumathi Sundaram - Sun Microsystems * can be the driver too due to lazy reclaim.
24737c478bd9Sstevel@tonic-gate */
24747c478bd9Sstevel@tonic-gate void
snf_smap_desbfree(snf_smap_desbinfo * snfi)24757c478bd9Sstevel@tonic-gate snf_smap_desbfree(snf_smap_desbinfo *snfi)
24767c478bd9Sstevel@tonic-gate {
24773b3d24f3SJayakara Kini if (! IS_KPM_ADDR(snfi->snfi_base)) {
24787c478bd9Sstevel@tonic-gate /*
24797c478bd9Sstevel@tonic-gate * We don't need to call segmap_fault(F_SOFTUNLOCK) for
24807c478bd9Sstevel@tonic-gate * segmap_kpm as long as the latter never falls back to
24817c478bd9Sstevel@tonic-gate * "use_segmap_range". (See segmap_getmapflt().)
24827c478bd9Sstevel@tonic-gate *
24837c478bd9Sstevel@tonic-gate * Using S_OTHER saves an redundant hat_setref() in
24847c478bd9Sstevel@tonic-gate * segmap_unlock()
24857c478bd9Sstevel@tonic-gate */
24867c478bd9Sstevel@tonic-gate (void) segmap_fault(kas.a_hat, segkmap,
24871e0267ddSkrgopi (caddr_t)(uintptr_t)(((uintptr_t)snfi->snfi_base +
24881e0267ddSkrgopi snfi->snfi_mapoff) & PAGEMASK), snfi->snfi_len,
24891e0267ddSkrgopi F_SOFTUNLOCK, S_OTHER);
24907c478bd9Sstevel@tonic-gate }
24917c478bd9Sstevel@tonic-gate (void) segmap_release(segkmap, snfi->snfi_base, SM_DONTNEED);
24927c478bd9Sstevel@tonic-gate VN_RELE(snfi->snfi_vp);
24937c478bd9Sstevel@tonic-gate kmem_free(snfi, sizeof (*snfi));
24947c478bd9Sstevel@tonic-gate }
24957c478bd9Sstevel@tonic-gate
24967c478bd9Sstevel@tonic-gate /*
2497ead83321SVasumathi Sundaram - Sun Microsystems * Use segmap or vpm instead of bcopy to send down a desballoca'ed, mblk.
2498ead83321SVasumathi Sundaram - Sun Microsystems * When segmap is used, the mblk contains a segmap slot of no more
2499ead83321SVasumathi Sundaram - Sun Microsystems * than MAXBSIZE.
2500ead83321SVasumathi Sundaram - Sun Microsystems *
2501ead83321SVasumathi Sundaram - Sun Microsystems * With vpm, a maximum of SNF_MAXVMAPS page-sized mappings can be obtained
2502ead83321SVasumathi Sundaram - Sun Microsystems * in each iteration and sent by socket_sendmblk until an error occurs or
2503ead83321SVasumathi Sundaram - Sun Microsystems * the requested size has been transferred. An mblk is esballoca'ed from
2504ead83321SVasumathi Sundaram - Sun Microsystems * each mapped page and a chain of these mblk is sent to the transport layer.
2505ead83321SVasumathi Sundaram - Sun Microsystems * vpm will be called to unmap the pages when all mblks have been freed by
2506ead83321SVasumathi Sundaram - Sun Microsystems * free_func.
25077c478bd9Sstevel@tonic-gate *
25087c478bd9Sstevel@tonic-gate * At the end of the whole sendfile() operation, we wait till the data from
25097c478bd9Sstevel@tonic-gate * the last mblk is ack'ed by the transport before returning so that the
25107c478bd9Sstevel@tonic-gate * caller of sendfile() can safely modify the file content.
25118cd31312SMarcel Telka *
25128cd31312SMarcel Telka * The caller of this function should make sure that total_size does not exceed
25138cd31312SMarcel Telka * the actual file size of fvp.
25147c478bd9Sstevel@tonic-gate */
25157c478bd9Sstevel@tonic-gate int
snf_segmap(file_t * fp,vnode_t * fvp,u_offset_t fileoff,u_offset_t total_size,ssize_t * count,boolean_t nowait)2516ead83321SVasumathi Sundaram - Sun Microsystems snf_segmap(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t total_size,
25173b3d24f3SJayakara Kini ssize_t *count, boolean_t nowait)
25187c478bd9Sstevel@tonic-gate {
25197c478bd9Sstevel@tonic-gate caddr_t base;
25207c478bd9Sstevel@tonic-gate int mapoff;
25217c478bd9Sstevel@tonic-gate vnode_t *vp;
2522ead83321SVasumathi Sundaram - Sun Microsystems mblk_t *mp = NULL;
2523ead83321SVasumathi Sundaram - Sun Microsystems int chain_size;
25247c478bd9Sstevel@tonic-gate int error;
252593b24f5eSBrian Utterback clock_t deadlk_wait;
25267c478bd9Sstevel@tonic-gate short fflag;
25277c478bd9Sstevel@tonic-gate int ksize;
25287c478bd9Sstevel@tonic-gate struct vattr va;
25297c478bd9Sstevel@tonic-gate boolean_t dowait = B_FALSE;
25300f1702c5SYu Xiangning struct nmsghdr msg;
25317c478bd9Sstevel@tonic-gate
25327c478bd9Sstevel@tonic-gate vp = fp->f_vnode;
25337c478bd9Sstevel@tonic-gate fflag = fp->f_flag;
25347c478bd9Sstevel@tonic-gate ksize = 0;
25350f1702c5SYu Xiangning bzero(&msg, sizeof (msg));
25360f1702c5SYu Xiangning
25377c478bd9Sstevel@tonic-gate for (;;) {
25387c478bd9Sstevel@tonic-gate if (ISSIG(curthread, JUSTLOOKING)) {
25397c478bd9Sstevel@tonic-gate error = EINTR;
25407c478bd9Sstevel@tonic-gate break;
25417c478bd9Sstevel@tonic-gate }
25427c478bd9Sstevel@tonic-gate
2543ead83321SVasumathi Sundaram - Sun Microsystems if (vpm_enable) {
2544ead83321SVasumathi Sundaram - Sun Microsystems snf_vmap_desbinfo *snfv;
2545ead83321SVasumathi Sundaram - Sun Microsystems mblk_t *nmp;
2546ead83321SVasumathi Sundaram - Sun Microsystems int mblk_size;
2547ead83321SVasumathi Sundaram - Sun Microsystems int maxsize;
2548ead83321SVasumathi Sundaram - Sun Microsystems int i;
2549ead83321SVasumathi Sundaram - Sun Microsystems
255031c2c73cSVasumathi Sundaram - Sun Microsystems mapoff = fileoff & PAGEOFFSET;
2551ead83321SVasumathi Sundaram - Sun Microsystems maxsize = MIN((SNF_VPMMAXPGS * PAGESIZE), total_size);
2552ead83321SVasumathi Sundaram - Sun Microsystems
2553ead83321SVasumathi Sundaram - Sun Microsystems snfv = kmem_zalloc(sizeof (snf_vmap_desbinfo),
2554ead83321SVasumathi Sundaram - Sun Microsystems KM_SLEEP);
255531c2c73cSVasumathi Sundaram - Sun Microsystems
255693b24f5eSBrian Utterback /*
255793b24f5eSBrian Utterback * Get vpm mappings for maxsize with read access.
255893b24f5eSBrian Utterback * If the pages aren't available yet, we get
255993b24f5eSBrian Utterback * DEADLK, so wait and try again a little later using
256093b24f5eSBrian Utterback * an increasing wait. We might be here a long time.
256193b24f5eSBrian Utterback *
256293b24f5eSBrian Utterback * If delay_sig returns EINTR, be sure to exit and
256393b24f5eSBrian Utterback * pass it up to the caller.
256493b24f5eSBrian Utterback */
256593b24f5eSBrian Utterback deadlk_wait = 0;
256693b24f5eSBrian Utterback while ((error = vpm_map_pages(fvp, fileoff,
256793b24f5eSBrian Utterback (size_t)maxsize, (VPM_FETCHPAGE), snfv->snfv_vml,
256893b24f5eSBrian Utterback SNF_MAXVMAPS, NULL, S_READ)) == EDEADLK) {
256993b24f5eSBrian Utterback deadlk_wait += (deadlk_wait < 5) ? 1 : 4;
257093b24f5eSBrian Utterback if ((error = delay_sig(deadlk_wait)) != 0) {
257193b24f5eSBrian Utterback break;
257293b24f5eSBrian Utterback }
257393b24f5eSBrian Utterback }
257493b24f5eSBrian Utterback if (error != 0) {
257531c2c73cSVasumathi Sundaram - Sun Microsystems kmem_free(snfv, sizeof (snf_vmap_desbinfo));
257693b24f5eSBrian Utterback error = (error == EINTR) ? EINTR : EIO;
257731c2c73cSVasumathi Sundaram - Sun Microsystems goto out;
257831c2c73cSVasumathi Sundaram - Sun Microsystems }
257931c2c73cSVasumathi Sundaram - Sun Microsystems snfv->snfv_frtn.free_func = snf_vmap_desbfree;
258031c2c73cSVasumathi Sundaram - Sun Microsystems snfv->snfv_frtn.free_arg = (caddr_t)snfv;
258131c2c73cSVasumathi Sundaram - Sun Microsystems
2582ead83321SVasumathi Sundaram - Sun Microsystems /* Construct the mblk chain from the page mappings */
2583ead83321SVasumathi Sundaram - Sun Microsystems chain_size = 0;
2584ead83321SVasumathi Sundaram - Sun Microsystems for (i = 0; (snfv->snfv_vml[i].vs_addr != NULL) &&
2585ead83321SVasumathi Sundaram - Sun Microsystems total_size > 0; i++) {
2586ead83321SVasumathi Sundaram - Sun Microsystems ASSERT(chain_size < maxsize);
2587ead83321SVasumathi Sundaram - Sun Microsystems mblk_size = MIN(snfv->snfv_vml[i].vs_len -
2588ead83321SVasumathi Sundaram - Sun Microsystems mapoff, total_size);
2589ead83321SVasumathi Sundaram - Sun Microsystems nmp = esballoca(
2590ead83321SVasumathi Sundaram - Sun Microsystems (uchar_t *)snfv->snfv_vml[i].vs_addr +
2591ead83321SVasumathi Sundaram - Sun Microsystems mapoff, mblk_size, BPRI_HI,
2592ead83321SVasumathi Sundaram - Sun Microsystems &snfv->snfv_frtn);
2593ead83321SVasumathi Sundaram - Sun Microsystems
2594ead83321SVasumathi Sundaram - Sun Microsystems /*
2595ead83321SVasumathi Sundaram - Sun Microsystems * We return EAGAIN after unmapping the pages
2596ead83321SVasumathi Sundaram - Sun Microsystems * if we cannot allocate the the head of the
2597ead83321SVasumathi Sundaram - Sun Microsystems * chain. Otherwise, we continue sending the
2598ead83321SVasumathi Sundaram - Sun Microsystems * mblks constructed so far.
2599ead83321SVasumathi Sundaram - Sun Microsystems */
2600ead83321SVasumathi Sundaram - Sun Microsystems if (nmp == NULL) {
2601ead83321SVasumathi Sundaram - Sun Microsystems if (i == 0) {
2602ead83321SVasumathi Sundaram - Sun Microsystems vpm_unmap_pages(snfv->snfv_vml,
2603ead83321SVasumathi Sundaram - Sun Microsystems S_READ);
2604ead83321SVasumathi Sundaram - Sun Microsystems kmem_free(snfv,
2605ead83321SVasumathi Sundaram - Sun Microsystems sizeof (snf_vmap_desbinfo));
2606ead83321SVasumathi Sundaram - Sun Microsystems error = EAGAIN;
2607ead83321SVasumathi Sundaram - Sun Microsystems goto out;
2608ead83321SVasumathi Sundaram - Sun Microsystems }
2609ead83321SVasumathi Sundaram - Sun Microsystems break;
261031c2c73cSVasumathi Sundaram - Sun Microsystems }
2611ead83321SVasumathi Sundaram - Sun Microsystems /* Mark this dblk with the zero-copy flag */
2612ead83321SVasumathi Sundaram - Sun Microsystems nmp->b_datap->db_struioflag |= STRUIO_ZC;
2613ead83321SVasumathi Sundaram - Sun Microsystems nmp->b_wptr += mblk_size;
2614ead83321SVasumathi Sundaram - Sun Microsystems chain_size += mblk_size;
2615ead83321SVasumathi Sundaram - Sun Microsystems fileoff += mblk_size;
2616ead83321SVasumathi Sundaram - Sun Microsystems total_size -= mblk_size;
2617ead83321SVasumathi Sundaram - Sun Microsystems snfv->snfv_ref++;
2618ead83321SVasumathi Sundaram - Sun Microsystems mapoff = 0;
2619ead83321SVasumathi Sundaram - Sun Microsystems if (i > 0)
2620ead83321SVasumathi Sundaram - Sun Microsystems linkb(mp, nmp);
2621ead83321SVasumathi Sundaram - Sun Microsystems else
2622ead83321SVasumathi Sundaram - Sun Microsystems mp = nmp;
262331c2c73cSVasumathi Sundaram - Sun Microsystems }
262431c2c73cSVasumathi Sundaram - Sun Microsystems VN_HOLD(fvp);
262531c2c73cSVasumathi Sundaram - Sun Microsystems snfv->snfv_vp = fvp;
262631c2c73cSVasumathi Sundaram - Sun Microsystems } else {
262731c2c73cSVasumathi Sundaram - Sun Microsystems /* vpm not supported. fallback to segmap */
2628ead83321SVasumathi Sundaram - Sun Microsystems snf_smap_desbinfo *snfi;
2629ead83321SVasumathi Sundaram - Sun Microsystems
263031c2c73cSVasumathi Sundaram - Sun Microsystems mapoff = fileoff & MAXBOFFSET;
2631ead83321SVasumathi Sundaram - Sun Microsystems chain_size = MAXBSIZE - mapoff;
2632ead83321SVasumathi Sundaram - Sun Microsystems if (chain_size > total_size)
2633ead83321SVasumathi Sundaram - Sun Microsystems chain_size = total_size;
263431c2c73cSVasumathi Sundaram - Sun Microsystems /*
263531c2c73cSVasumathi Sundaram - Sun Microsystems * we don't forcefault because we'll call
263631c2c73cSVasumathi Sundaram - Sun Microsystems * segmap_fault(F_SOFTLOCK) next.
263731c2c73cSVasumathi Sundaram - Sun Microsystems *
263831c2c73cSVasumathi Sundaram - Sun Microsystems * S_READ will get the ref bit set (by either
263931c2c73cSVasumathi Sundaram - Sun Microsystems * segmap_getmapflt() or segmap_fault()) and page
264031c2c73cSVasumathi Sundaram - Sun Microsystems * shared locked.
264131c2c73cSVasumathi Sundaram - Sun Microsystems */
2642ead83321SVasumathi Sundaram - Sun Microsystems base = segmap_getmapflt(segkmap, fvp, fileoff,
2643ead83321SVasumathi Sundaram - Sun Microsystems chain_size, segmap_kpm ? SM_FAULT : 0, S_READ);
26443b3d24f3SJayakara Kini
264531c2c73cSVasumathi Sundaram - Sun Microsystems snfi = kmem_alloc(sizeof (*snfi), KM_SLEEP);
2646ead83321SVasumathi Sundaram - Sun Microsystems snfi->snfi_len = (size_t)roundup(mapoff+chain_size,
264731c2c73cSVasumathi Sundaram - Sun Microsystems PAGESIZE)- (mapoff & PAGEMASK);
264831c2c73cSVasumathi Sundaram - Sun Microsystems /*
264931c2c73cSVasumathi Sundaram - Sun Microsystems * We must call segmap_fault() even for segmap_kpm
265031c2c73cSVasumathi Sundaram - Sun Microsystems * because that's how error gets returned.
265131c2c73cSVasumathi Sundaram - Sun Microsystems * (segmap_getmapflt() never fails but segmap_fault()
265231c2c73cSVasumathi Sundaram - Sun Microsystems * does.)
265393b24f5eSBrian Utterback *
265493b24f5eSBrian Utterback * If the pages aren't available yet, we get
265593b24f5eSBrian Utterback * DEADLK, so wait and try again a little later using
265693b24f5eSBrian Utterback * an increasing wait. We might be here a long time.
265793b24f5eSBrian Utterback *
265893b24f5eSBrian Utterback * If delay_sig returns EINTR, be sure to exit and
265993b24f5eSBrian Utterback * pass it up to the caller.
266031c2c73cSVasumathi Sundaram - Sun Microsystems */
266193b24f5eSBrian Utterback deadlk_wait = 0;
266293b24f5eSBrian Utterback while ((error = FC_ERRNO(segmap_fault(kas.a_hat,
266393b24f5eSBrian Utterback segkmap, (caddr_t)(uintptr_t)(((uintptr_t)base +
266493b24f5eSBrian Utterback mapoff) & PAGEMASK), snfi->snfi_len, F_SOFTLOCK,
266593b24f5eSBrian Utterback S_READ))) == EDEADLK) {
266693b24f5eSBrian Utterback deadlk_wait += (deadlk_wait < 5) ? 1 : 4;
266793b24f5eSBrian Utterback if ((error = delay_sig(deadlk_wait)) != 0) {
266893b24f5eSBrian Utterback break;
266993b24f5eSBrian Utterback }
267093b24f5eSBrian Utterback }
267193b24f5eSBrian Utterback if (error != 0) {
267231c2c73cSVasumathi Sundaram - Sun Microsystems (void) segmap_release(segkmap, base, 0);
267331c2c73cSVasumathi Sundaram - Sun Microsystems kmem_free(snfi, sizeof (*snfi));
267493b24f5eSBrian Utterback error = (error == EINTR) ? EINTR : EIO;
267531c2c73cSVasumathi Sundaram - Sun Microsystems goto out;
267631c2c73cSVasumathi Sundaram - Sun Microsystems }
267731c2c73cSVasumathi Sundaram - Sun Microsystems snfi->snfi_frtn.free_func = snf_smap_desbfree;
267831c2c73cSVasumathi Sundaram - Sun Microsystems snfi->snfi_frtn.free_arg = (caddr_t)snfi;
267931c2c73cSVasumathi Sundaram - Sun Microsystems snfi->snfi_base = base;
268031c2c73cSVasumathi Sundaram - Sun Microsystems snfi->snfi_mapoff = mapoff;
2681ead83321SVasumathi Sundaram - Sun Microsystems mp = esballoca((uchar_t *)base + mapoff, chain_size,
268231c2c73cSVasumathi Sundaram - Sun Microsystems BPRI_HI, &snfi->snfi_frtn);
268331c2c73cSVasumathi Sundaram - Sun Microsystems
268431c2c73cSVasumathi Sundaram - Sun Microsystems if (mp == NULL) {
268531c2c73cSVasumathi Sundaram - Sun Microsystems (void) segmap_fault(kas.a_hat, segkmap,
2686ead83321SVasumathi Sundaram - Sun Microsystems (caddr_t)(uintptr_t)(((uintptr_t)base +
2687ead83321SVasumathi Sundaram - Sun Microsystems mapoff) & PAGEMASK), snfi->snfi_len,
268831c2c73cSVasumathi Sundaram - Sun Microsystems F_SOFTUNLOCK, S_OTHER);
268931c2c73cSVasumathi Sundaram - Sun Microsystems (void) segmap_release(segkmap, base, 0);
269031c2c73cSVasumathi Sundaram - Sun Microsystems kmem_free(snfi, sizeof (*snfi));
269131c2c73cSVasumathi Sundaram - Sun Microsystems freemsg(mp);
269231c2c73cSVasumathi Sundaram - Sun Microsystems error = EAGAIN;
269331c2c73cSVasumathi Sundaram - Sun Microsystems goto out;
269431c2c73cSVasumathi Sundaram - Sun Microsystems }
269531c2c73cSVasumathi Sundaram - Sun Microsystems VN_HOLD(fvp);
269631c2c73cSVasumathi Sundaram - Sun Microsystems snfi->snfi_vp = fvp;
2697ead83321SVasumathi Sundaram - Sun Microsystems mp->b_wptr += chain_size;
269831c2c73cSVasumathi Sundaram - Sun Microsystems
269931c2c73cSVasumathi Sundaram - Sun Microsystems /* Mark this dblk with the zero-copy flag */
270031c2c73cSVasumathi Sundaram - Sun Microsystems mp->b_datap->db_struioflag |= STRUIO_ZC;
2701ead83321SVasumathi Sundaram - Sun Microsystems fileoff += chain_size;
2702ead83321SVasumathi Sundaram - Sun Microsystems total_size -= chain_size;
27033b3d24f3SJayakara Kini }
27047c478bd9Sstevel@tonic-gate
2705ead83321SVasumathi Sundaram - Sun Microsystems if (total_size == 0 && !nowait) {
27067c478bd9Sstevel@tonic-gate ASSERT(!dowait);
27077c478bd9Sstevel@tonic-gate dowait = B_TRUE;
27083b3d24f3SJayakara Kini mp->b_datap->db_struioflag |= STRUIO_ZCNOTIFY;
27097c478bd9Sstevel@tonic-gate }
27107c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
27110f1702c5SYu Xiangning error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp);
27120f1702c5SYu Xiangning if (error != 0) {
2713ead83321SVasumathi Sundaram - Sun Microsystems /*
2714ead83321SVasumathi Sundaram - Sun Microsystems * mp contains the mblks that were not sent by
2715ead83321SVasumathi Sundaram - Sun Microsystems * socket_sendmblk. Use its size to update *count
2716ead83321SVasumathi Sundaram - Sun Microsystems */
2717ead83321SVasumathi Sundaram - Sun Microsystems *count = ksize + (chain_size - msgdsize(mp));
27180f1702c5SYu Xiangning if (mp != NULL)
27190f1702c5SYu Xiangning freemsg(mp);
27207c478bd9Sstevel@tonic-gate return (error);
27217c478bd9Sstevel@tonic-gate }
2722ead83321SVasumathi Sundaram - Sun Microsystems ksize += chain_size;
2723ead83321SVasumathi Sundaram - Sun Microsystems if (total_size == 0)
27247c478bd9Sstevel@tonic-gate goto done;
27257c478bd9Sstevel@tonic-gate
27267c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
27277c478bd9Sstevel@tonic-gate va.va_mask = AT_SIZE;
2728da6c28aaSamw error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
27297c478bd9Sstevel@tonic-gate if (error)
27307c478bd9Sstevel@tonic-gate break;
27317c478bd9Sstevel@tonic-gate /* Read as much as possible. */
27327c478bd9Sstevel@tonic-gate if (fileoff >= va.va_size)
27337c478bd9Sstevel@tonic-gate break;
2734ead83321SVasumathi Sundaram - Sun Microsystems if (total_size + fileoff > va.va_size)
2735ead83321SVasumathi Sundaram - Sun Microsystems total_size = va.va_size - fileoff;
27367c478bd9Sstevel@tonic-gate }
27377c478bd9Sstevel@tonic-gate out:
27387c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
27397c478bd9Sstevel@tonic-gate done:
27407c478bd9Sstevel@tonic-gate *count = ksize;
27417c478bd9Sstevel@tonic-gate if (dowait) {
27427c478bd9Sstevel@tonic-gate stdata_t *stp;
27437c478bd9Sstevel@tonic-gate
27447c478bd9Sstevel@tonic-gate stp = vp->v_stream;
27450f1702c5SYu Xiangning if (stp == NULL) {
27460f1702c5SYu Xiangning struct sonode *so;
27470f1702c5SYu Xiangning so = VTOSO(vp);
27480f1702c5SYu Xiangning error = so_zcopy_wait(so);
27490f1702c5SYu Xiangning } else {
27500f1702c5SYu Xiangning mutex_enter(&stp->sd_lock);
27510f1702c5SYu Xiangning while (!(stp->sd_flag & STZCNOTIFY)) {
27520f1702c5SYu Xiangning if (cv_wait_sig(&stp->sd_zcopy_wait,
27530f1702c5SYu Xiangning &stp->sd_lock) == 0) {
27540f1702c5SYu Xiangning error = EINTR;
27550f1702c5SYu Xiangning break;
27560f1702c5SYu Xiangning }
2757a298cf18Samehta }
27580f1702c5SYu Xiangning stp->sd_flag &= ~STZCNOTIFY;
27590f1702c5SYu Xiangning mutex_exit(&stp->sd_lock);
27607c478bd9Sstevel@tonic-gate }
27617c478bd9Sstevel@tonic-gate }
27627c478bd9Sstevel@tonic-gate return (error);
27637c478bd9Sstevel@tonic-gate }
27647c478bd9Sstevel@tonic-gate
27657c478bd9Sstevel@tonic-gate int
snf_cache(file_t * fp,vnode_t * fvp,u_offset_t fileoff,u_offset_t size,uint_t maxpsz,ssize_t * count)27667c478bd9Sstevel@tonic-gate snf_cache(file_t *fp, vnode_t *fvp, u_offset_t fileoff, u_offset_t size,
27677c478bd9Sstevel@tonic-gate uint_t maxpsz, ssize_t *count)
27687c478bd9Sstevel@tonic-gate {
27697c478bd9Sstevel@tonic-gate struct vnode *vp;
27707c478bd9Sstevel@tonic-gate mblk_t *mp;
27717c478bd9Sstevel@tonic-gate int iosize;
2772b273e065Skrishna int extra = 0;
27737c478bd9Sstevel@tonic-gate int error;
27747c478bd9Sstevel@tonic-gate short fflag;
27757c478bd9Sstevel@tonic-gate int ksize;
27767c478bd9Sstevel@tonic-gate int ioflag;
27777c478bd9Sstevel@tonic-gate struct uio auio;
27787c478bd9Sstevel@tonic-gate struct iovec aiov;
27797c478bd9Sstevel@tonic-gate struct vattr va;
2780e116a42fSPrakash Jalan int maxblk = 0;
2781e116a42fSPrakash Jalan int wroff = 0;
2782e116a42fSPrakash Jalan struct sonode *so;
27830f1702c5SYu Xiangning struct nmsghdr msg;
27847c478bd9Sstevel@tonic-gate
27857c478bd9Sstevel@tonic-gate vp = fp->f_vnode;
2786b273e065Skrishna if (vp->v_type == VSOCK) {
2787b273e065Skrishna stdata_t *stp;
2788b273e065Skrishna
2789b273e065Skrishna /*
2790b273e065Skrishna * Get the extra space to insert a header and a trailer.
2791b273e065Skrishna */
2792e116a42fSPrakash Jalan so = VTOSO(vp);
2793b273e065Skrishna stp = vp->v_stream;
27940f1702c5SYu Xiangning if (stp == NULL) {
27950f1702c5SYu Xiangning wroff = so->so_proto_props.sopp_wroff;
27960f1702c5SYu Xiangning maxblk = so->so_proto_props.sopp_maxblk;
27970f1702c5SYu Xiangning extra = wroff + so->so_proto_props.sopp_tail;
27980f1702c5SYu Xiangning } else {
27990f1702c5SYu Xiangning wroff = (int)(stp->sd_wroff);
28000f1702c5SYu Xiangning maxblk = (int)(stp->sd_maxblk);
28010f1702c5SYu Xiangning extra = wroff + (int)(stp->sd_tail);
28020f1702c5SYu Xiangning }
2803b273e065Skrishna }
28040f1702c5SYu Xiangning bzero(&msg, sizeof (msg));
28057c478bd9Sstevel@tonic-gate fflag = fp->f_flag;
28067c478bd9Sstevel@tonic-gate ksize = 0;
28077c478bd9Sstevel@tonic-gate auio.uio_iov = &aiov;
28087c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1;
28097c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_SYSSPACE;
28107c478bd9Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T;
28117c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag;
28127c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_CACHED;
28137c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & (FSYNC|FDSYNC|FRSYNC);
28147c478bd9Sstevel@tonic-gate /* If read sync is not asked for, filter sync flags */
28157c478bd9Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0)
28167c478bd9Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC);
28177c478bd9Sstevel@tonic-gate for (;;) {
28187c478bd9Sstevel@tonic-gate if (ISSIG(curthread, JUSTLOOKING)) {
28197c478bd9Sstevel@tonic-gate error = EINTR;
28207c478bd9Sstevel@tonic-gate break;
28217c478bd9Sstevel@tonic-gate }
28227c478bd9Sstevel@tonic-gate iosize = (int)MIN(maxpsz, size);
2823e116a42fSPrakash Jalan
2824e116a42fSPrakash Jalan /*
28253e95bd4aSAnders Persson * Socket filters can limit the mblk size,
28263e95bd4aSAnders Persson * so limit reads to maxblk if there are
2827dd49f125SAnders Persson * filters present.
2828e116a42fSPrakash Jalan */
28293e95bd4aSAnders Persson if (vp->v_type == VSOCK &&
28303e95bd4aSAnders Persson so->so_filter_active > 0 && maxblk != INFPSZ)
2831e116a42fSPrakash Jalan iosize = (int)MIN(iosize, maxblk);
2832e116a42fSPrakash Jalan
2833de8c4a14SErik Nordmark if (is_system_labeled()) {
2834de8c4a14SErik Nordmark mp = allocb_cred(iosize + extra, CRED(),
2835de8c4a14SErik Nordmark curproc->p_pid);
2836de8c4a14SErik Nordmark } else {
2837de8c4a14SErik Nordmark mp = allocb(iosize + extra, BPRI_MED);
2838de8c4a14SErik Nordmark }
2839de8c4a14SErik Nordmark if (mp == NULL) {
28407c478bd9Sstevel@tonic-gate error = EAGAIN;
28417c478bd9Sstevel@tonic-gate break;
28427c478bd9Sstevel@tonic-gate }
2843e116a42fSPrakash Jalan
2844e116a42fSPrakash Jalan mp->b_rptr += wroff;
2845e116a42fSPrakash Jalan
28467c478bd9Sstevel@tonic-gate aiov.iov_base = (caddr_t)mp->b_rptr;
28477c478bd9Sstevel@tonic-gate aiov.iov_len = iosize;
28487c478bd9Sstevel@tonic-gate auio.uio_loffset = fileoff;
28497c478bd9Sstevel@tonic-gate auio.uio_resid = iosize;
28507c478bd9Sstevel@tonic-gate
28517c478bd9Sstevel@tonic-gate error = VOP_READ(fvp, &auio, ioflag, fp->f_cred, NULL);
28527c478bd9Sstevel@tonic-gate iosize -= auio.uio_resid;
28537c478bd9Sstevel@tonic-gate
28547c478bd9Sstevel@tonic-gate if (error == EINTR && iosize != 0)
28557c478bd9Sstevel@tonic-gate error = 0;
28567c478bd9Sstevel@tonic-gate
28577c478bd9Sstevel@tonic-gate if (error != 0 || iosize == 0) {
28587c478bd9Sstevel@tonic-gate freeb(mp);
28597c478bd9Sstevel@tonic-gate break;
28607c478bd9Sstevel@tonic-gate }
28617c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + iosize;
28627c478bd9Sstevel@tonic-gate
28637c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
28640f1702c5SYu Xiangning
28650f1702c5SYu Xiangning error = socket_sendmblk(VTOSO(vp), &msg, fflag, CRED(), &mp);
28660f1702c5SYu Xiangning
28670f1702c5SYu Xiangning if (error != 0) {
28687c478bd9Sstevel@tonic-gate *count = ksize;
28690f1702c5SYu Xiangning if (mp != NULL)
28700f1702c5SYu Xiangning freeb(mp);
28717c478bd9Sstevel@tonic-gate return (error);
28727c478bd9Sstevel@tonic-gate }
28737c478bd9Sstevel@tonic-gate ksize += iosize;
28747c478bd9Sstevel@tonic-gate size -= iosize;
28757c478bd9Sstevel@tonic-gate if (size == 0)
28767c478bd9Sstevel@tonic-gate goto done;
28777c478bd9Sstevel@tonic-gate
28787c478bd9Sstevel@tonic-gate fileoff += iosize;
28797c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
28807c478bd9Sstevel@tonic-gate va.va_mask = AT_SIZE;
2881da6c28aaSamw error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
28827c478bd9Sstevel@tonic-gate if (error)
28837c478bd9Sstevel@tonic-gate break;
28847c478bd9Sstevel@tonic-gate /* Read as much as possible. */
28857c478bd9Sstevel@tonic-gate if (fileoff >= va.va_size)
28867c478bd9Sstevel@tonic-gate size = 0;
28877c478bd9Sstevel@tonic-gate else if (size + fileoff > va.va_size)
28887c478bd9Sstevel@tonic-gate size = va.va_size - fileoff;
28897c478bd9Sstevel@tonic-gate }
28907c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
28917c478bd9Sstevel@tonic-gate done:
28927c478bd9Sstevel@tonic-gate *count = ksize;
28937c478bd9Sstevel@tonic-gate return (error);
28947c478bd9Sstevel@tonic-gate }
28957c478bd9Sstevel@tonic-gate
28967c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) || defined(_ILP32)
28977c478bd9Sstevel@tonic-gate /*
28987c478bd9Sstevel@tonic-gate * Largefile support for 32 bit applications only.
28997c478bd9Sstevel@tonic-gate */
29007c478bd9Sstevel@tonic-gate int
sosendfile64(file_t * fp,file_t * rfp,const struct ksendfilevec64 * sfv,ssize32_t * count32)29017c478bd9Sstevel@tonic-gate sosendfile64(file_t *fp, file_t *rfp, const struct ksendfilevec64 *sfv,
29027c478bd9Sstevel@tonic-gate ssize32_t *count32)
29037c478bd9Sstevel@tonic-gate {
29047c478bd9Sstevel@tonic-gate ssize32_t sfv_len;
29057c478bd9Sstevel@tonic-gate u_offset_t sfv_off, va_size;
29067c478bd9Sstevel@tonic-gate struct vnode *vp, *fvp, *realvp;
29077c478bd9Sstevel@tonic-gate struct vattr va;
29087c478bd9Sstevel@tonic-gate stdata_t *stp;
29097c478bd9Sstevel@tonic-gate ssize_t count = 0;
29107c478bd9Sstevel@tonic-gate int error = 0;
29117c478bd9Sstevel@tonic-gate boolean_t dozcopy = B_FALSE;
29127c478bd9Sstevel@tonic-gate uint_t maxpsz;
29137c478bd9Sstevel@tonic-gate
29147c478bd9Sstevel@tonic-gate sfv_len = (ssize32_t)sfv->sfv_len;
29157c478bd9Sstevel@tonic-gate if (sfv_len < 0) {
29167c478bd9Sstevel@tonic-gate error = EINVAL;
29177c478bd9Sstevel@tonic-gate goto out;
29187c478bd9Sstevel@tonic-gate }
29197c478bd9Sstevel@tonic-gate
29207c478bd9Sstevel@tonic-gate if (sfv_len == 0) goto out;
29217c478bd9Sstevel@tonic-gate
29227c478bd9Sstevel@tonic-gate sfv_off = (u_offset_t)sfv->sfv_off;
29237c478bd9Sstevel@tonic-gate
29247c478bd9Sstevel@tonic-gate /* Same checks as in pread */
29257c478bd9Sstevel@tonic-gate if (sfv_off > MAXOFFSET_T) {
29267c478bd9Sstevel@tonic-gate error = EINVAL;
29277c478bd9Sstevel@tonic-gate goto out;
29287c478bd9Sstevel@tonic-gate }
29297c478bd9Sstevel@tonic-gate if (sfv_off + sfv_len > MAXOFFSET_T)
29307c478bd9Sstevel@tonic-gate sfv_len = (ssize32_t)(MAXOFFSET_T - sfv_off);
29317c478bd9Sstevel@tonic-gate
29327c478bd9Sstevel@tonic-gate /*
29337c478bd9Sstevel@tonic-gate * There are no more checks on sfv_len. So, we cast it to
29347c478bd9Sstevel@tonic-gate * u_offset_t and share the snf_direct_io/snf_cache code between
29357c478bd9Sstevel@tonic-gate * 32 bit and 64 bit.
29367c478bd9Sstevel@tonic-gate *
29377c478bd9Sstevel@tonic-gate * TODO: should do nbl_need_check() like read()?
29387c478bd9Sstevel@tonic-gate */
29397c478bd9Sstevel@tonic-gate if (sfv_len > sendfile_max_size) {
29407c478bd9Sstevel@tonic-gate sf_stats.ss_file_not_cached++;
29417c478bd9Sstevel@tonic-gate error = snf_direct_io(fp, rfp, sfv_off, (u_offset_t)sfv_len,
29427c478bd9Sstevel@tonic-gate &count);
29437c478bd9Sstevel@tonic-gate goto out;
29447c478bd9Sstevel@tonic-gate }
29457c478bd9Sstevel@tonic-gate fvp = rfp->f_vnode;
2946da6c28aaSamw if (VOP_REALVP(fvp, &realvp, NULL) == 0)
29477c478bd9Sstevel@tonic-gate fvp = realvp;
29487c478bd9Sstevel@tonic-gate /*
29497c478bd9Sstevel@tonic-gate * Grab the lock as a reader to prevent the file size
29507c478bd9Sstevel@tonic-gate * from changing underneath.
29517c478bd9Sstevel@tonic-gate */
29527c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(fvp, V_WRITELOCK_FALSE, NULL);
29537c478bd9Sstevel@tonic-gate va.va_mask = AT_SIZE;
2954da6c28aaSamw error = VOP_GETATTR(fvp, &va, 0, kcred, NULL);
29557c478bd9Sstevel@tonic-gate va_size = va.va_size;
2956a8e93a73Sdm if ((error != 0) || (va_size == 0) || (sfv_off >= va_size)) {
29577c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(fvp, V_WRITELOCK_FALSE, NULL);
29587c478bd9Sstevel@tonic-gate goto out;
29597c478bd9Sstevel@tonic-gate }
29607c478bd9Sstevel@tonic-gate /* Read as much as possible. */
29617c478bd9Sstevel@tonic-gate if (sfv_off + sfv_len > va_size)
29627c478bd9Sstevel@tonic-gate sfv_len = va_size - sfv_off;
29637c478bd9Sstevel@tonic-gate
29647c478bd9Sstevel@tonic-gate vp = fp->f_vnode;
29657c478bd9Sstevel@tonic-gate stp = vp->v_stream;
29667c478bd9Sstevel@tonic-gate /*
29677c478bd9Sstevel@tonic-gate * When the NOWAIT flag is not set, we enable zero-copy only if the
29687c478bd9Sstevel@tonic-gate * transfer size is large enough. This prevents performance loss
29697c478bd9Sstevel@tonic-gate * when the caller sends the file piece by piece.
29707c478bd9Sstevel@tonic-gate */
29717c478bd9Sstevel@tonic-gate if (sfv_len >= MAXBSIZE && (sfv_len >= (va_size >> 1) ||
29727c478bd9Sstevel@tonic-gate (sfv->sfv_flag & SFV_NOWAIT) || sfv_len >= 0x1000000) &&
297374024373Spr !vn_has_flocks(fvp) && !(fvp->v_flag & VNOMAP)) {
29740f1702c5SYu Xiangning uint_t copyflag;
29750f1702c5SYu Xiangning copyflag = stp != NULL ? stp->sd_copyflag :
29760f1702c5SYu Xiangning VTOSO(vp)->so_proto_props.sopp_zcopyflag;
29770f1702c5SYu Xiangning if ((copyflag & (STZCVMSAFE|STZCVMUNSAFE)) == 0) {
29787c478bd9Sstevel@tonic-gate int on = 1;
29797c478bd9Sstevel@tonic-gate
29800f1702c5SYu Xiangning if (socket_setsockopt(VTOSO(vp), SOL_SOCKET,
29810f1702c5SYu Xiangning SO_SND_COPYAVOID, &on, sizeof (on), CRED()) == 0)
29827c478bd9Sstevel@tonic-gate dozcopy = B_TRUE;
29837c478bd9Sstevel@tonic-gate } else {
29840f1702c5SYu Xiangning dozcopy = copyflag & STZCVMSAFE;
29857c478bd9Sstevel@tonic-gate }
29867c478bd9Sstevel@tonic-gate }
29877c478bd9Sstevel@tonic-gate if (dozcopy) {
29887c478bd9Sstevel@tonic-gate sf_stats.ss_file_segmap++;
29897c478bd9Sstevel@tonic-gate error = snf_segmap(fp, fvp, sfv_off, (u_offset_t)sfv_len,
29903b3d24f3SJayakara Kini &count, ((sfv->sfv_flag & SFV_NOWAIT) != 0));
29917c478bd9Sstevel@tonic-gate } else {
29920f1702c5SYu Xiangning if (vp->v_type == VSOCK && stp == NULL) {
29930f1702c5SYu Xiangning sonode_t *so = VTOSO(vp);
29940f1702c5SYu Xiangning maxpsz = so->so_proto_props.sopp_maxpsz;
29950f1702c5SYu Xiangning } else if (stp != NULL) {
29960f1702c5SYu Xiangning maxpsz = stp->sd_qn_maxpsz;
29970f1702c5SYu Xiangning } else {
29980f1702c5SYu Xiangning maxpsz = maxphys;
29990f1702c5SYu Xiangning }
30000f1702c5SYu Xiangning
30010f1702c5SYu Xiangning if (maxpsz == INFPSZ)
30023b3d24f3SJayakara Kini maxpsz = maxphys;
30033b3d24f3SJayakara Kini else
30040f1702c5SYu Xiangning maxpsz = roundup(maxpsz, MAXBSIZE);
30057c478bd9Sstevel@tonic-gate sf_stats.ss_file_cached++;
30067c478bd9Sstevel@tonic-gate error = snf_cache(fp, fvp, sfv_off, (u_offset_t)sfv_len,
30077c478bd9Sstevel@tonic-gate maxpsz, &count);
30087c478bd9Sstevel@tonic-gate }
30097c478bd9Sstevel@tonic-gate out:
30107c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd);
30117c478bd9Sstevel@tonic-gate *count32 = (ssize32_t)count;
30127c478bd9Sstevel@tonic-gate return (error);
30137c478bd9Sstevel@tonic-gate }
30147c478bd9Sstevel@tonic-gate #endif
30157c478bd9Sstevel@tonic-gate
30167c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
30177c478bd9Sstevel@tonic-gate /*
30187c478bd9Sstevel@tonic-gate * recv32(), recvfrom32(), send32(), sendto32(): intentionally return a
30197c478bd9Sstevel@tonic-gate * ssize_t rather than ssize32_t; see the comments above read32 for details.
30207c478bd9Sstevel@tonic-gate */
30217c478bd9Sstevel@tonic-gate
30227c478bd9Sstevel@tonic-gate ssize_t
recv32(int32_t sock,caddr32_t buffer,size32_t len,int32_t flags)30237c478bd9Sstevel@tonic-gate recv32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags)
30247c478bd9Sstevel@tonic-gate {
30257c478bd9Sstevel@tonic-gate return (recv(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags));
30267c478bd9Sstevel@tonic-gate }
30277c478bd9Sstevel@tonic-gate
30287c478bd9Sstevel@tonic-gate ssize_t
recvfrom32(int32_t sock,caddr32_t buffer,size32_t len,int32_t flags,caddr32_t name,caddr32_t namelenp)30297c478bd9Sstevel@tonic-gate recvfrom32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags,
30308cd31312SMarcel Telka caddr32_t name, caddr32_t namelenp)
30317c478bd9Sstevel@tonic-gate {
30327c478bd9Sstevel@tonic-gate return (recvfrom(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags,
30337c478bd9Sstevel@tonic-gate (void *)(uintptr_t)name, (void *)(uintptr_t)namelenp));
30347c478bd9Sstevel@tonic-gate }
30357c478bd9Sstevel@tonic-gate
30367c478bd9Sstevel@tonic-gate ssize_t
send32(int32_t sock,caddr32_t buffer,size32_t len,int32_t flags)30377c478bd9Sstevel@tonic-gate send32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags)
30387c478bd9Sstevel@tonic-gate {
30397c478bd9Sstevel@tonic-gate return (send(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags));
30407c478bd9Sstevel@tonic-gate }
30417c478bd9Sstevel@tonic-gate
30427c478bd9Sstevel@tonic-gate ssize_t
sendto32(int32_t sock,caddr32_t buffer,size32_t len,int32_t flags,caddr32_t name,socklen_t namelen)30437c478bd9Sstevel@tonic-gate sendto32(int32_t sock, caddr32_t buffer, size32_t len, int32_t flags,
30448cd31312SMarcel Telka caddr32_t name, socklen_t namelen)
30457c478bd9Sstevel@tonic-gate {
30467c478bd9Sstevel@tonic-gate return (sendto(sock, (void *)(uintptr_t)buffer, (ssize32_t)len, flags,
30477c478bd9Sstevel@tonic-gate (void *)(uintptr_t)name, namelen));
30487c478bd9Sstevel@tonic-gate }
30497c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
30507c478bd9Sstevel@tonic-gate
30517c478bd9Sstevel@tonic-gate /*
3052da6c28aaSamw * Function wrappers (mostly around the sonode switch) for
30537c478bd9Sstevel@tonic-gate * backward compatibility.
30547c478bd9Sstevel@tonic-gate */
30557c478bd9Sstevel@tonic-gate
30567c478bd9Sstevel@tonic-gate int
soaccept(struct sonode * so,int fflag,struct sonode ** nsop)30577c478bd9Sstevel@tonic-gate soaccept(struct sonode *so, int fflag, struct sonode **nsop)
30587c478bd9Sstevel@tonic-gate {
30590f1702c5SYu Xiangning return (socket_accept(so, fflag, CRED(), nsop));
30607c478bd9Sstevel@tonic-gate }
30617c478bd9Sstevel@tonic-gate
30627c478bd9Sstevel@tonic-gate int
sobind(struct sonode * so,struct sockaddr * name,socklen_t namelen,int backlog,int flags)30637c478bd9Sstevel@tonic-gate sobind(struct sonode *so, struct sockaddr *name, socklen_t namelen,
30647c478bd9Sstevel@tonic-gate int backlog, int flags)
30657c478bd9Sstevel@tonic-gate {
30667c478bd9Sstevel@tonic-gate int error;
30677c478bd9Sstevel@tonic-gate
30680f1702c5SYu Xiangning error = socket_bind(so, name, namelen, flags, CRED());
30697c478bd9Sstevel@tonic-gate if (error == 0 && backlog != 0)
30700f1702c5SYu Xiangning return (socket_listen(so, backlog, CRED()));
30717c478bd9Sstevel@tonic-gate
30727c478bd9Sstevel@tonic-gate return (error);
30737c478bd9Sstevel@tonic-gate }
30747c478bd9Sstevel@tonic-gate
30757c478bd9Sstevel@tonic-gate int
solisten(struct sonode * so,int backlog)30767c478bd9Sstevel@tonic-gate solisten(struct sonode *so, int backlog)
30777c478bd9Sstevel@tonic-gate {
30780f1702c5SYu Xiangning return (socket_listen(so, backlog, CRED()));
30797c478bd9Sstevel@tonic-gate }
30807c478bd9Sstevel@tonic-gate
30817c478bd9Sstevel@tonic-gate int
soconnect(struct sonode * so,struct sockaddr * name,socklen_t namelen,int fflag,int flags)30823e95bd4aSAnders Persson soconnect(struct sonode *so, struct sockaddr *name, socklen_t namelen,
30837c478bd9Sstevel@tonic-gate int fflag, int flags)
30847c478bd9Sstevel@tonic-gate {
30850f1702c5SYu Xiangning return (socket_connect(so, name, namelen, fflag, flags, CRED()));
30867c478bd9Sstevel@tonic-gate }
30877c478bd9Sstevel@tonic-gate
30887c478bd9Sstevel@tonic-gate int
sorecvmsg(struct sonode * so,struct nmsghdr * msg,struct uio * uiop)30897c478bd9Sstevel@tonic-gate sorecvmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop)
30907c478bd9Sstevel@tonic-gate {
30910f1702c5SYu Xiangning return (socket_recvmsg(so, msg, uiop, CRED()));
30927c478bd9Sstevel@tonic-gate }
30937c478bd9Sstevel@tonic-gate
30947c478bd9Sstevel@tonic-gate int
sosendmsg(struct sonode * so,struct nmsghdr * msg,struct uio * uiop)30957c478bd9Sstevel@tonic-gate sosendmsg(struct sonode *so, struct nmsghdr *msg, struct uio *uiop)
30967c478bd9Sstevel@tonic-gate {
30970f1702c5SYu Xiangning return (socket_sendmsg(so, msg, uiop, CRED()));
30987c478bd9Sstevel@tonic-gate }
30997c478bd9Sstevel@tonic-gate
31007c478bd9Sstevel@tonic-gate int
soshutdown(struct sonode * so,int how)31017c478bd9Sstevel@tonic-gate soshutdown(struct sonode *so, int how)
31027c478bd9Sstevel@tonic-gate {
31030f1702c5SYu Xiangning return (socket_shutdown(so, how, CRED()));
31047c478bd9Sstevel@tonic-gate }
31057c478bd9Sstevel@tonic-gate
31067c478bd9Sstevel@tonic-gate int
sogetsockopt(struct sonode * so,int level,int option_name,void * optval,socklen_t * optlenp,int flags)31077c478bd9Sstevel@tonic-gate sogetsockopt(struct sonode *so, int level, int option_name, void *optval,
31087c478bd9Sstevel@tonic-gate socklen_t *optlenp, int flags)
31097c478bd9Sstevel@tonic-gate {
31100f1702c5SYu Xiangning return (socket_getsockopt(so, level, option_name, optval, optlenp,
31110f1702c5SYu Xiangning flags, CRED()));
31127c478bd9Sstevel@tonic-gate }
31137c478bd9Sstevel@tonic-gate
31147c478bd9Sstevel@tonic-gate int
sosetsockopt(struct sonode * so,int level,int option_name,const void * optval,t_uscalar_t optlen)31157c478bd9Sstevel@tonic-gate sosetsockopt(struct sonode *so, int level, int option_name, const void *optval,
31167c478bd9Sstevel@tonic-gate t_uscalar_t optlen)
31177c478bd9Sstevel@tonic-gate {
31180f1702c5SYu Xiangning return (socket_setsockopt(so, level, option_name, optval, optlen,
31190f1702c5SYu Xiangning CRED()));
31207c478bd9Sstevel@tonic-gate }
31217c478bd9Sstevel@tonic-gate
31227c478bd9Sstevel@tonic-gate /*
31237c478bd9Sstevel@tonic-gate * Because this is backward compatibility interface it only needs to be
31247c478bd9Sstevel@tonic-gate * able to handle the creation of TPI sockfs sockets.
31257c478bd9Sstevel@tonic-gate */
31267c478bd9Sstevel@tonic-gate struct sonode *
socreate(struct sockparams * sp,int family,int type,int protocol,int version,int * errorp)31270f1702c5SYu Xiangning socreate(struct sockparams *sp, int family, int type, int protocol, int version,
31280f1702c5SYu Xiangning int *errorp)
31297c478bd9Sstevel@tonic-gate {
31300f1702c5SYu Xiangning struct sonode *so;
31310f1702c5SYu Xiangning
31320f1702c5SYu Xiangning ASSERT(sp != NULL);
31330f1702c5SYu Xiangning
31340f1702c5SYu Xiangning so = sp->sp_smod_info->smod_sock_create_func(sp, family, type, protocol,
31350f1702c5SYu Xiangning version, SOCKET_SLEEP, errorp, CRED());
31360f1702c5SYu Xiangning if (so == NULL) {
31370f1702c5SYu Xiangning SOCKPARAMS_DEC_REF(sp);
31380f1702c5SYu Xiangning } else {
31390f1702c5SYu Xiangning if ((*errorp = SOP_INIT(so, NULL, CRED(), SOCKET_SLEEP)) == 0) {
31400f1702c5SYu Xiangning /* Cannot fail, only bumps so_count */
31410f1702c5SYu Xiangning (void) VOP_OPEN(&SOTOV(so), FREAD|FWRITE, CRED(), NULL);
31420f1702c5SYu Xiangning } else {
31430f1702c5SYu Xiangning socket_destroy(so);
31440f1702c5SYu Xiangning so = NULL;
31450f1702c5SYu Xiangning }
31460f1702c5SYu Xiangning }
31470f1702c5SYu Xiangning return (so);
31487c478bd9Sstevel@tonic-gate }
3149