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
545916cd2Sjpk * Common Development and Distribution License (the "License").
645916cd2Sjpk * 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 */
217c478bd9Sstevel@tonic-gate /*
22de8c4a14SErik Nordmark * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
287c478bd9Sstevel@tonic-gate * All Rights Reserved
297c478bd9Sstevel@tonic-gate */
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD
337c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California.
347c478bd9Sstevel@tonic-gate */
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate * Implements a kernel based, client side RPC over Connection Oriented
397c478bd9Sstevel@tonic-gate * Transports (COTS).
407c478bd9Sstevel@tonic-gate */
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate * Much of this file has been re-written to let NFS work better over slow
447c478bd9Sstevel@tonic-gate * transports. A description follows.
457c478bd9Sstevel@tonic-gate *
467c478bd9Sstevel@tonic-gate * One of the annoying things about kRPC/COTS is that it will temporarily
477c478bd9Sstevel@tonic-gate * create more than one connection between a client and server. This
487c478bd9Sstevel@tonic-gate * happens because when a connection is made, the end-points entry in the
497c478bd9Sstevel@tonic-gate * linked list of connections (headed by cm_hd), is removed so that other
507c478bd9Sstevel@tonic-gate * threads don't mess with it. Went ahead and bit the bullet by keeping
517c478bd9Sstevel@tonic-gate * the endpoint on the connection list and introducing state bits,
527c478bd9Sstevel@tonic-gate * condition variables etc. to the connection entry data structure (struct
537c478bd9Sstevel@tonic-gate * cm_xprt).
547c478bd9Sstevel@tonic-gate *
557c478bd9Sstevel@tonic-gate * Here is a summary of the changes to cm-xprt:
567c478bd9Sstevel@tonic-gate *
577c478bd9Sstevel@tonic-gate * x_ctime is the timestamp of when the endpoint was last
587c478bd9Sstevel@tonic-gate * connected or disconnected. If an end-point is ever disconnected
597c478bd9Sstevel@tonic-gate * or re-connected, then any outstanding RPC request is presumed
607c478bd9Sstevel@tonic-gate * lost, telling clnt_cots_kcallit that it needs to re-send the
617c478bd9Sstevel@tonic-gate * request, not just wait for the original request's reply to
627c478bd9Sstevel@tonic-gate * arrive.
637c478bd9Sstevel@tonic-gate *
647c478bd9Sstevel@tonic-gate * x_thread flag which tells us if a thread is doing a connection attempt.
657c478bd9Sstevel@tonic-gate *
667c478bd9Sstevel@tonic-gate * x_waitdis flag which tells us we are waiting a disconnect ACK.
677c478bd9Sstevel@tonic-gate *
687c478bd9Sstevel@tonic-gate * x_needdis flag which tells us we need to send a T_DISCONN_REQ
697c478bd9Sstevel@tonic-gate * to kill the connection.
707c478bd9Sstevel@tonic-gate *
717c478bd9Sstevel@tonic-gate * x_needrel flag which tells us we need to send a T_ORDREL_REQ to
727c478bd9Sstevel@tonic-gate * gracefully close the connection.
737c478bd9Sstevel@tonic-gate *
747c478bd9Sstevel@tonic-gate * #defined bitmasks for the all the b_* bits so that more
757c478bd9Sstevel@tonic-gate * efficient (and at times less clumsy) masks can be used to
767c478bd9Sstevel@tonic-gate * manipulated state in cases where multiple bits have to
777c478bd9Sstevel@tonic-gate * set/cleared/checked in the same critical section.
787c478bd9Sstevel@tonic-gate *
797c478bd9Sstevel@tonic-gate * x_conn_cv and x_dis-_cv are new condition variables to let
807c478bd9Sstevel@tonic-gate * threads knows when the connection attempt is done, and to let
817c478bd9Sstevel@tonic-gate * the connecting thread know when the disconnect handshake is
827c478bd9Sstevel@tonic-gate * done.
837c478bd9Sstevel@tonic-gate *
847c478bd9Sstevel@tonic-gate * Added the CONN_HOLD() macro so that all reference holds have the same
857c478bd9Sstevel@tonic-gate * look and feel.
867c478bd9Sstevel@tonic-gate *
877c478bd9Sstevel@tonic-gate * In the private (cku_private) portion of the client handle,
887c478bd9Sstevel@tonic-gate *
897c478bd9Sstevel@tonic-gate * cku_flags replaces the cku_sent a boolean. cku_flags keeps
907c478bd9Sstevel@tonic-gate * track of whether a request as been sent, and whether the
917c478bd9Sstevel@tonic-gate * client's handles call record is on the dispatch list (so that
927c478bd9Sstevel@tonic-gate * the reply can be matched by XID to the right client handle).
937c478bd9Sstevel@tonic-gate * The idea of CKU_ONQUEUE is that we can exit clnt_cots_kcallit()
947c478bd9Sstevel@tonic-gate * and still have the response find the right client handle so
957c478bd9Sstevel@tonic-gate * that the retry of CLNT_CALL() gets the result. Testing, found
967c478bd9Sstevel@tonic-gate * situations where if the timeout was increased, performance
977c478bd9Sstevel@tonic-gate * degraded. This was due to us hitting a window where the thread
987c478bd9Sstevel@tonic-gate * was back in rfscall() (probably printing server not responding)
997c478bd9Sstevel@tonic-gate * while the response came back but no place to put it.
1007c478bd9Sstevel@tonic-gate *
1017c478bd9Sstevel@tonic-gate * cku_ctime is just a cache of x_ctime. If they match,
1027c478bd9Sstevel@tonic-gate * clnt_cots_kcallit() won't to send a retry (unless the maximum
1037c478bd9Sstevel@tonic-gate * receive count limit as been reached). If the don't match, then
1047c478bd9Sstevel@tonic-gate * we assume the request has been lost, and a retry of the request
1057c478bd9Sstevel@tonic-gate * is needed.
1067c478bd9Sstevel@tonic-gate *
1077c478bd9Sstevel@tonic-gate * cku_recv_attempts counts the number of receive count attempts
1087c478bd9Sstevel@tonic-gate * after one try is sent on the wire.
1097c478bd9Sstevel@tonic-gate *
1107c478bd9Sstevel@tonic-gate * Added the clnt_delay() routine so that interruptible and
1117c478bd9Sstevel@tonic-gate * noninterruptible delays are possible.
1127c478bd9Sstevel@tonic-gate *
1137c478bd9Sstevel@tonic-gate * CLNT_MIN_TIMEOUT has been bumped to 10 seconds from 3. This is used to
1147c478bd9Sstevel@tonic-gate * control how long the client delays before returned after getting
1157c478bd9Sstevel@tonic-gate * ECONNREFUSED. At 3 seconds, 8 client threads per mount really does bash
1167c478bd9Sstevel@tonic-gate * a server that may be booting and not yet started nfsd.
1177c478bd9Sstevel@tonic-gate *
1187c478bd9Sstevel@tonic-gate * CLNT_MAXRECV_WITHOUT_RETRY is a new macro (value of 3) (with a tunable)
1197c478bd9Sstevel@tonic-gate * Why don't we just wait forever (receive an infinite # of times)?
1207c478bd9Sstevel@tonic-gate * Because the server may have rebooted. More insidious is that some
1217c478bd9Sstevel@tonic-gate * servers (ours) will drop NFS/TCP requests in some cases. This is bad,
1227c478bd9Sstevel@tonic-gate * but it is a reality.
1237c478bd9Sstevel@tonic-gate *
1247c478bd9Sstevel@tonic-gate * The case of a server doing orderly release really messes up the
1257c478bd9Sstevel@tonic-gate * client's recovery, especially if the server's TCP implementation is
1267c478bd9Sstevel@tonic-gate * buggy. It was found was that the kRPC/COTS client was breaking some
1277c478bd9Sstevel@tonic-gate * TPI rules, such as not waiting for the acknowledgement of a
1287c478bd9Sstevel@tonic-gate * T_DISCON_REQ (hence the added case statements T_ERROR_ACK, T_OK_ACK and
1297c478bd9Sstevel@tonic-gate * T_DISCON_REQ in clnt_dispatch_notifyall()).
1307c478bd9Sstevel@tonic-gate *
1317c478bd9Sstevel@tonic-gate * One of things that we've seen is that a kRPC TCP endpoint goes into
1327c478bd9Sstevel@tonic-gate * TIMEWAIT and a thus a reconnect takes a long time to satisfy because
1337c478bd9Sstevel@tonic-gate * that the TIMEWAIT state takes a while to finish. If a server sends a
1347c478bd9Sstevel@tonic-gate * T_ORDREL_IND, there is little point in an RPC client doing a
1357c478bd9Sstevel@tonic-gate * T_ORDREL_REQ, because the RPC request isn't going to make it (the
1367c478bd9Sstevel@tonic-gate * server is saying that it won't accept any more data). So kRPC was
1377c478bd9Sstevel@tonic-gate * changed to send a T_DISCON_REQ when we get a T_ORDREL_IND. So now the
1387c478bd9Sstevel@tonic-gate * connection skips the TIMEWAIT state and goes straight to a bound state
1397c478bd9Sstevel@tonic-gate * that kRPC can quickly switch to connected.
1407c478bd9Sstevel@tonic-gate *
1417c478bd9Sstevel@tonic-gate * Code that issues TPI request must use waitforack() to wait for the
1427c478bd9Sstevel@tonic-gate * corresponding ack (assuming there is one) in any future modifications.
1437c478bd9Sstevel@tonic-gate * This works around problems that may be introduced by breaking TPI rules
1447c478bd9Sstevel@tonic-gate * (by submitting new calls before earlier requests have been acked) in the
1457c478bd9Sstevel@tonic-gate * case of a signal or other early return. waitforack() depends on
1467c478bd9Sstevel@tonic-gate * clnt_dispatch_notifyconn() to issue the wakeup when the ack
1477c478bd9Sstevel@tonic-gate * arrives, so adding new TPI calls may require corresponding changes
1487c478bd9Sstevel@tonic-gate * to clnt_dispatch_notifyconn(). Presently, the timeout period is based on
1497c478bd9Sstevel@tonic-gate * CLNT_MIN_TIMEOUT which is 10 seconds. If you modify this value, be sure
1507c478bd9Sstevel@tonic-gate * not to set it too low or TPI ACKS will be lost.
1517c478bd9Sstevel@tonic-gate */
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate #include <sys/param.h>
1547c478bd9Sstevel@tonic-gate #include <sys/types.h>
1557c478bd9Sstevel@tonic-gate #include <sys/user.h>
1567c478bd9Sstevel@tonic-gate #include <sys/systm.h>
1577c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
1587c478bd9Sstevel@tonic-gate #include <sys/proc.h>
1597c478bd9Sstevel@tonic-gate #include <sys/socket.h>
1607c478bd9Sstevel@tonic-gate #include <sys/file.h>
1617c478bd9Sstevel@tonic-gate #include <sys/stream.h>
1627c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
1637c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
1647c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
1657c478bd9Sstevel@tonic-gate #include <sys/timod.h>
1667c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
1677c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
1687c478bd9Sstevel@tonic-gate #include <sys/t_kuser.h>
1697c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
1707c478bd9Sstevel@tonic-gate #include <sys/errno.h>
1717c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
1727c478bd9Sstevel@tonic-gate #include <sys/debug.h>
1737c478bd9Sstevel@tonic-gate #include <sys/systm.h>
1747c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
1757c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
1767c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
1777c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
1787c478bd9Sstevel@tonic-gate #include <sys/time.h>
1797c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
1807c478bd9Sstevel@tonic-gate #include <sys/callb.h>
1817c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
1827c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
183125a8fd9SSiddheshwar Mahesh #include <sys/sdt.h>
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate #include <netinet/in.h>
1867c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate #include <rpc/types.h>
1897c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
1907c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
1917c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
1927c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.h>
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate #define COTS_DEFAULT_ALLOCSIZE 2048
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate #define WIRE_HDR_SIZE 20 /* serialized call header, sans proc number */
1977c478bd9Sstevel@tonic-gate #define MSG_OFFSET 128 /* offset of call into the mblk */
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate const char *kinet_ntop6(uchar_t *, char *, size_t);
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate static int clnt_cots_ksettimers(CLIENT *, struct rpc_timers *,
2027c478bd9Sstevel@tonic-gate struct rpc_timers *, int, void(*)(int, int, caddr_t), caddr_t, uint32_t);
2037c478bd9Sstevel@tonic-gate static enum clnt_stat clnt_cots_kcallit(CLIENT *, rpcproc_t, xdrproc_t,
2047c478bd9Sstevel@tonic-gate caddr_t, xdrproc_t, caddr_t, struct timeval);
2057c478bd9Sstevel@tonic-gate static void clnt_cots_kabort(CLIENT *);
2067c478bd9Sstevel@tonic-gate static void clnt_cots_kerror(CLIENT *, struct rpc_err *);
2077c478bd9Sstevel@tonic-gate static bool_t clnt_cots_kfreeres(CLIENT *, xdrproc_t, caddr_t);
2087c478bd9Sstevel@tonic-gate static void clnt_cots_kdestroy(CLIENT *);
2097c478bd9Sstevel@tonic-gate static bool_t clnt_cots_kcontrol(CLIENT *, int, char *);
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate /* List of transports managed by the connection manager. */
2137c478bd9Sstevel@tonic-gate struct cm_xprt {
2147c478bd9Sstevel@tonic-gate TIUSER *x_tiptr; /* transport handle */
2157c478bd9Sstevel@tonic-gate queue_t *x_wq; /* send queue */
2167c478bd9Sstevel@tonic-gate clock_t x_time; /* last time we handed this xprt out */
2177c478bd9Sstevel@tonic-gate clock_t x_ctime; /* time we went to CONNECTED */
2187c478bd9Sstevel@tonic-gate int x_tidu_size; /* TIDU size of this transport */
2197c478bd9Sstevel@tonic-gate union {
2207c478bd9Sstevel@tonic-gate struct {
2217c478bd9Sstevel@tonic-gate unsigned int
2227c478bd9Sstevel@tonic-gate #ifdef _BIT_FIELDS_HTOL
2237c478bd9Sstevel@tonic-gate b_closing: 1, /* we've sent a ord rel on this conn */
2247c478bd9Sstevel@tonic-gate b_dead: 1, /* transport is closed or disconn */
2257c478bd9Sstevel@tonic-gate b_doomed: 1, /* too many conns, let this go idle */
2267c478bd9Sstevel@tonic-gate b_connected: 1, /* this connection is connected */
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate b_ordrel: 1, /* do an orderly release? */
2297c478bd9Sstevel@tonic-gate b_thread: 1, /* thread doing connect */
2307c478bd9Sstevel@tonic-gate b_waitdis: 1, /* waiting for disconnect ACK */
2317c478bd9Sstevel@tonic-gate b_needdis: 1, /* need T_DISCON_REQ */
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate b_needrel: 1, /* need T_ORDREL_REQ */
2347c478bd9Sstevel@tonic-gate b_early_disc: 1, /* got a T_ORDREL_IND or T_DISCON_IND */
2357c478bd9Sstevel@tonic-gate /* disconnect during connect */
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate b_pad: 22;
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate #endif
2407c478bd9Sstevel@tonic-gate
2417c478bd9Sstevel@tonic-gate #ifdef _BIT_FIELDS_LTOH
2427c478bd9Sstevel@tonic-gate b_pad: 22,
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate b_early_disc: 1, /* got a T_ORDREL_IND or T_DISCON_IND */
2457c478bd9Sstevel@tonic-gate /* disconnect during connect */
2467c478bd9Sstevel@tonic-gate b_needrel: 1, /* need T_ORDREL_REQ */
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate b_needdis: 1, /* need T_DISCON_REQ */
2497c478bd9Sstevel@tonic-gate b_waitdis: 1, /* waiting for disconnect ACK */
2507c478bd9Sstevel@tonic-gate b_thread: 1, /* thread doing connect */
2517c478bd9Sstevel@tonic-gate b_ordrel: 1, /* do an orderly release? */
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate b_connected: 1, /* this connection is connected */
2547c478bd9Sstevel@tonic-gate b_doomed: 1, /* too many conns, let this go idle */
2557c478bd9Sstevel@tonic-gate b_dead: 1, /* transport is closed or disconn */
2567c478bd9Sstevel@tonic-gate b_closing: 1; /* we've sent a ord rel on this conn */
2577c478bd9Sstevel@tonic-gate #endif
2587c478bd9Sstevel@tonic-gate } bit; unsigned int word;
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate #define x_closing x_state.bit.b_closing
2617c478bd9Sstevel@tonic-gate #define x_dead x_state.bit.b_dead
2627c478bd9Sstevel@tonic-gate #define x_doomed x_state.bit.b_doomed
2637c478bd9Sstevel@tonic-gate #define x_connected x_state.bit.b_connected
2647c478bd9Sstevel@tonic-gate
2657c478bd9Sstevel@tonic-gate #define x_ordrel x_state.bit.b_ordrel
2667c478bd9Sstevel@tonic-gate #define x_thread x_state.bit.b_thread
2677c478bd9Sstevel@tonic-gate #define x_waitdis x_state.bit.b_waitdis
2687c478bd9Sstevel@tonic-gate #define x_needdis x_state.bit.b_needdis
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate #define x_needrel x_state.bit.b_needrel
2717c478bd9Sstevel@tonic-gate #define x_early_disc x_state.bit.b_early_disc
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate #define x_state_flags x_state.word
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate #define X_CLOSING 0x80000000
2767c478bd9Sstevel@tonic-gate #define X_DEAD 0x40000000
2777c478bd9Sstevel@tonic-gate #define X_DOOMED 0x20000000
2787c478bd9Sstevel@tonic-gate #define X_CONNECTED 0x10000000
2797c478bd9Sstevel@tonic-gate
2807c478bd9Sstevel@tonic-gate #define X_ORDREL 0x08000000
2817c478bd9Sstevel@tonic-gate #define X_THREAD 0x04000000
2827c478bd9Sstevel@tonic-gate #define X_WAITDIS 0x02000000
2837c478bd9Sstevel@tonic-gate #define X_NEEDDIS 0x01000000
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate #define X_NEEDREL 0x00800000
2867c478bd9Sstevel@tonic-gate #define X_EARLYDISC 0x00400000
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate #define X_BADSTATES (X_CLOSING | X_DEAD | X_DOOMED)
2897c478bd9Sstevel@tonic-gate
2907c478bd9Sstevel@tonic-gate } x_state;
2917c478bd9Sstevel@tonic-gate int x_ref; /* number of users of this xprt */
2927c478bd9Sstevel@tonic-gate int x_family; /* address family of transport */
2937c478bd9Sstevel@tonic-gate dev_t x_rdev; /* device number of transport */
2947c478bd9Sstevel@tonic-gate struct cm_xprt *x_next;
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate struct netbuf x_server; /* destination address */
2977c478bd9Sstevel@tonic-gate struct netbuf x_src; /* src address (for retries) */
2987c478bd9Sstevel@tonic-gate kmutex_t x_lock; /* lock on this entry */
2997c478bd9Sstevel@tonic-gate kcondvar_t x_cv; /* to signal when can be closed */
3007c478bd9Sstevel@tonic-gate kcondvar_t x_conn_cv; /* to signal when connection attempt */
3017c478bd9Sstevel@tonic-gate /* is complete */
3027c478bd9Sstevel@tonic-gate kstat_t *x_ksp;
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate kcondvar_t x_dis_cv; /* to signal when disconnect attempt */
3057c478bd9Sstevel@tonic-gate /* is complete */
3067c478bd9Sstevel@tonic-gate zoneid_t x_zoneid; /* zone this xprt belongs to */
3077c478bd9Sstevel@tonic-gate };
3087c478bd9Sstevel@tonic-gate
3097c478bd9Sstevel@tonic-gate typedef struct cm_kstat_xprt {
3107c478bd9Sstevel@tonic-gate kstat_named_t x_wq;
3117c478bd9Sstevel@tonic-gate kstat_named_t x_server;
3127c478bd9Sstevel@tonic-gate kstat_named_t x_family;
3137c478bd9Sstevel@tonic-gate kstat_named_t x_rdev;
3147c478bd9Sstevel@tonic-gate kstat_named_t x_time;
3157c478bd9Sstevel@tonic-gate kstat_named_t x_state;
3167c478bd9Sstevel@tonic-gate kstat_named_t x_ref;
3177c478bd9Sstevel@tonic-gate kstat_named_t x_port;
3187c478bd9Sstevel@tonic-gate } cm_kstat_xprt_t;
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate static cm_kstat_xprt_t cm_kstat_template = {
3217c478bd9Sstevel@tonic-gate { "write_queue", KSTAT_DATA_UINT32 },
3227c478bd9Sstevel@tonic-gate { "server", KSTAT_DATA_STRING },
3237c478bd9Sstevel@tonic-gate { "addr_family", KSTAT_DATA_UINT32 },
3247c478bd9Sstevel@tonic-gate { "device", KSTAT_DATA_UINT32 },
3257c478bd9Sstevel@tonic-gate { "time_stamp", KSTAT_DATA_UINT32 },
3267c478bd9Sstevel@tonic-gate { "status", KSTAT_DATA_UINT32 },
3277c478bd9Sstevel@tonic-gate { "ref_count", KSTAT_DATA_INT32 },
3287c478bd9Sstevel@tonic-gate { "port", KSTAT_DATA_UINT32 },
3297c478bd9Sstevel@tonic-gate };
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate /*
3327c478bd9Sstevel@tonic-gate * The inverse of this is connmgr_release().
3337c478bd9Sstevel@tonic-gate */
3347c478bd9Sstevel@tonic-gate #define CONN_HOLD(Cm_entry) {\
3357c478bd9Sstevel@tonic-gate mutex_enter(&(Cm_entry)->x_lock); \
3367c478bd9Sstevel@tonic-gate (Cm_entry)->x_ref++; \
3377c478bd9Sstevel@tonic-gate mutex_exit(&(Cm_entry)->x_lock); \
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate /*
3427c478bd9Sstevel@tonic-gate * Private data per rpc handle. This structure is allocated by
3437c478bd9Sstevel@tonic-gate * clnt_cots_kcreate, and freed by clnt_cots_kdestroy.
3447c478bd9Sstevel@tonic-gate */
3457c478bd9Sstevel@tonic-gate typedef struct cku_private_s {
3467c478bd9Sstevel@tonic-gate CLIENT cku_client; /* client handle */
3477c478bd9Sstevel@tonic-gate calllist_t cku_call; /* for dispatching calls */
3487c478bd9Sstevel@tonic-gate struct rpc_err cku_err; /* error status */
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate struct netbuf cku_srcaddr; /* source address for retries */
3517c478bd9Sstevel@tonic-gate int cku_addrfmly; /* for binding port */
3527c478bd9Sstevel@tonic-gate struct netbuf cku_addr; /* remote address */
3537c478bd9Sstevel@tonic-gate dev_t cku_device; /* device to use */
3547c478bd9Sstevel@tonic-gate uint_t cku_flags;
3557c478bd9Sstevel@tonic-gate #define CKU_ONQUEUE 0x1
3567c478bd9Sstevel@tonic-gate #define CKU_SENT 0x2
3577c478bd9Sstevel@tonic-gate
3587c478bd9Sstevel@tonic-gate bool_t cku_progress; /* for CLSET_PROGRESS */
3597c478bd9Sstevel@tonic-gate uint32_t cku_xid; /* current XID */
3607c478bd9Sstevel@tonic-gate clock_t cku_ctime; /* time stamp of when */
3617c478bd9Sstevel@tonic-gate /* connection was created */
3627c478bd9Sstevel@tonic-gate uint_t cku_recv_attempts;
3637c478bd9Sstevel@tonic-gate XDR cku_outxdr; /* xdr routine for output */
3647c478bd9Sstevel@tonic-gate XDR cku_inxdr; /* xdr routine for input */
3657c478bd9Sstevel@tonic-gate char cku_rpchdr[WIRE_HDR_SIZE + 4];
3667c478bd9Sstevel@tonic-gate /* pre-serialized rpc header */
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate uint_t cku_outbuflen; /* default output mblk length */
3697c478bd9Sstevel@tonic-gate struct cred *cku_cred; /* credentials */
3707c478bd9Sstevel@tonic-gate bool_t cku_nodelayonerr;
3717c478bd9Sstevel@tonic-gate /* for CLSET_NODELAYONERR */
3727c478bd9Sstevel@tonic-gate int cku_useresvport; /* Use reserved port */
3737c478bd9Sstevel@tonic-gate struct rpc_cots_client *cku_stats; /* stats for zone */
3747c478bd9Sstevel@tonic-gate } cku_private_t;
3757c478bd9Sstevel@tonic-gate
3767c478bd9Sstevel@tonic-gate static struct cm_xprt *connmgr_wrapconnect(struct cm_xprt *,
3777c478bd9Sstevel@tonic-gate const struct timeval *, struct netbuf *, int, struct netbuf *,
378de8c4a14SErik Nordmark struct rpc_err *, bool_t, bool_t, cred_t *);
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate static bool_t connmgr_connect(struct cm_xprt *, queue_t *, struct netbuf *,
3817c478bd9Sstevel@tonic-gate int, calllist_t *, int *, bool_t reconnect,
382de8c4a14SErik Nordmark const struct timeval *, bool_t, cred_t *);
3837c478bd9Sstevel@tonic-gate
3842081ac19SDai Ngo static void *connmgr_opt_getoff(mblk_t *mp, t_uscalar_t offset,
3852081ac19SDai Ngo t_uscalar_t length, uint_t align_size);
3862081ac19SDai Ngo static bool_t connmgr_setbufsz(calllist_t *e, queue_t *wq, cred_t *cr);
3872081ac19SDai Ngo static bool_t connmgr_getopt_int(queue_t *wq, int level, int name, int *val,
3882081ac19SDai Ngo calllist_t *e, cred_t *cr);
3892081ac19SDai Ngo static bool_t connmgr_setopt_int(queue_t *wq, int level, int name, int val,
3902081ac19SDai Ngo calllist_t *e, cred_t *cr);
391de8c4a14SErik Nordmark static bool_t connmgr_setopt(queue_t *, int, int, calllist_t *, cred_t *cr);
3927c478bd9Sstevel@tonic-gate static void connmgr_sndrel(struct cm_xprt *);
3937c478bd9Sstevel@tonic-gate static void connmgr_snddis(struct cm_xprt *);
3947c478bd9Sstevel@tonic-gate static void connmgr_close(struct cm_xprt *);
3957c478bd9Sstevel@tonic-gate static void connmgr_release(struct cm_xprt *);
3967c478bd9Sstevel@tonic-gate static struct cm_xprt *connmgr_wrapget(struct netbuf *, const struct timeval *,
3977c478bd9Sstevel@tonic-gate cku_private_t *);
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate static struct cm_xprt *connmgr_get(struct netbuf *, const struct timeval *,
4007c478bd9Sstevel@tonic-gate struct netbuf *, int, struct netbuf *, struct rpc_err *, dev_t,
401de8c4a14SErik Nordmark bool_t, int, cred_t *);
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate static void connmgr_cancelconn(struct cm_xprt *);
4047c478bd9Sstevel@tonic-gate static enum clnt_stat connmgr_cwait(struct cm_xprt *, const struct timeval *,
4057c478bd9Sstevel@tonic-gate bool_t);
4067c478bd9Sstevel@tonic-gate static void connmgr_dis_and_wait(struct cm_xprt *);
4077c478bd9Sstevel@tonic-gate
408125a8fd9SSiddheshwar Mahesh static int clnt_dispatch_send(queue_t *, mblk_t *, calllist_t *, uint_t,
4097c478bd9Sstevel@tonic-gate uint_t);
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate static int clnt_delay(clock_t, bool_t);
4127c478bd9Sstevel@tonic-gate
4137c478bd9Sstevel@tonic-gate static int waitforack(calllist_t *, t_scalar_t, const struct timeval *, bool_t);
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate /*
4167c478bd9Sstevel@tonic-gate * Operations vector for TCP/IP based RPC
4177c478bd9Sstevel@tonic-gate */
4187c478bd9Sstevel@tonic-gate static struct clnt_ops tcp_ops = {
4197c478bd9Sstevel@tonic-gate clnt_cots_kcallit, /* do rpc call */
4207c478bd9Sstevel@tonic-gate clnt_cots_kabort, /* abort call */
4217c478bd9Sstevel@tonic-gate clnt_cots_kerror, /* return error status */
4227c478bd9Sstevel@tonic-gate clnt_cots_kfreeres, /* free results */
4237c478bd9Sstevel@tonic-gate clnt_cots_kdestroy, /* destroy rpc handle */
4247c478bd9Sstevel@tonic-gate clnt_cots_kcontrol, /* the ioctl() of rpc */
4257c478bd9Sstevel@tonic-gate clnt_cots_ksettimers, /* set retry timers */
4267c478bd9Sstevel@tonic-gate };
4277c478bd9Sstevel@tonic-gate
4287c478bd9Sstevel@tonic-gate static int rpc_kstat_instance = 0; /* keeps the current instance */
4297c478bd9Sstevel@tonic-gate /* number for the next kstat_create */
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate static struct cm_xprt *cm_hd = NULL;
4327c478bd9Sstevel@tonic-gate static kmutex_t connmgr_lock; /* for connection mngr's list of transports */
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate extern kmutex_t clnt_max_msg_lock;
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate static calllist_t *clnt_pending = NULL;
4377c478bd9Sstevel@tonic-gate extern kmutex_t clnt_pending_lock;
4387c478bd9Sstevel@tonic-gate
4397c478bd9Sstevel@tonic-gate static int clnt_cots_hash_size = DEFAULT_HASH_SIZE;
4407c478bd9Sstevel@tonic-gate
4417c478bd9Sstevel@tonic-gate static call_table_t *cots_call_ht;
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate static const struct rpc_cots_client {
4447c478bd9Sstevel@tonic-gate kstat_named_t rccalls;
4457c478bd9Sstevel@tonic-gate kstat_named_t rcbadcalls;
4467c478bd9Sstevel@tonic-gate kstat_named_t rcbadxids;
4477c478bd9Sstevel@tonic-gate kstat_named_t rctimeouts;
4487c478bd9Sstevel@tonic-gate kstat_named_t rcnewcreds;
4497c478bd9Sstevel@tonic-gate kstat_named_t rcbadverfs;
4507c478bd9Sstevel@tonic-gate kstat_named_t rctimers;
4517c478bd9Sstevel@tonic-gate kstat_named_t rccantconn;
4527c478bd9Sstevel@tonic-gate kstat_named_t rcnomem;
4537c478bd9Sstevel@tonic-gate kstat_named_t rcintrs;
4547c478bd9Sstevel@tonic-gate } cots_rcstat_tmpl = {
4557c478bd9Sstevel@tonic-gate { "calls", KSTAT_DATA_UINT64 },
4567c478bd9Sstevel@tonic-gate { "badcalls", KSTAT_DATA_UINT64 },
4577c478bd9Sstevel@tonic-gate { "badxids", KSTAT_DATA_UINT64 },
4587c478bd9Sstevel@tonic-gate { "timeouts", KSTAT_DATA_UINT64 },
4597c478bd9Sstevel@tonic-gate { "newcreds", KSTAT_DATA_UINT64 },
4607c478bd9Sstevel@tonic-gate { "badverfs", KSTAT_DATA_UINT64 },
4617c478bd9Sstevel@tonic-gate { "timers", KSTAT_DATA_UINT64 },
4627c478bd9Sstevel@tonic-gate { "cantconn", KSTAT_DATA_UINT64 },
4637c478bd9Sstevel@tonic-gate { "nomem", KSTAT_DATA_UINT64 },
4647c478bd9Sstevel@tonic-gate { "interrupts", KSTAT_DATA_UINT64 }
4657c478bd9Sstevel@tonic-gate };
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate #define COTSRCSTAT_INCR(p, x) \
468*1a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&(p)->x.value.ui64)
4697c478bd9Sstevel@tonic-gate
4707c478bd9Sstevel@tonic-gate #define CLNT_MAX_CONNS 1 /* concurrent connections between clnt/srvr */
47181dbf0b5SDai Ngo int clnt_max_conns = CLNT_MAX_CONNS;
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate #define CLNT_MIN_TIMEOUT 10 /* seconds to wait after we get a */
4747c478bd9Sstevel@tonic-gate /* connection reset */
4757c478bd9Sstevel@tonic-gate #define CLNT_MIN_CONNTIMEOUT 5 /* seconds to wait for a connection */
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gate
47881dbf0b5SDai Ngo int clnt_cots_min_tout = CLNT_MIN_TIMEOUT;
47981dbf0b5SDai Ngo int clnt_cots_min_conntout = CLNT_MIN_CONNTIMEOUT;
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate /*
4827c478bd9Sstevel@tonic-gate * Limit the number of times we will attempt to receive a reply without
4837c478bd9Sstevel@tonic-gate * re-sending a response.
4847c478bd9Sstevel@tonic-gate */
4857c478bd9Sstevel@tonic-gate #define CLNT_MAXRECV_WITHOUT_RETRY 3
48681dbf0b5SDai Ngo uint_t clnt_cots_maxrecv = CLNT_MAXRECV_WITHOUT_RETRY;
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate uint_t *clnt_max_msg_sizep;
4897c478bd9Sstevel@tonic-gate void (*clnt_stop_idle)(queue_t *wq);
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate #define ptoh(p) (&((p)->cku_client))
4927c478bd9Sstevel@tonic-gate #define htop(h) ((cku_private_t *)((h)->cl_private))
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate /*
4957c478bd9Sstevel@tonic-gate * Times to retry
4967c478bd9Sstevel@tonic-gate */
4977c478bd9Sstevel@tonic-gate #define REFRESHES 2 /* authentication refreshes */
4987c478bd9Sstevel@tonic-gate
4995bd9f8f1Srg137905 /*
5005bd9f8f1Srg137905 * The following is used to determine the global default behavior for
5015bd9f8f1Srg137905 * COTS when binding to a local port.
5025bd9f8f1Srg137905 *
5035bd9f8f1Srg137905 * If the value is set to 1 the default will be to select a reserved
5045bd9f8f1Srg137905 * (aka privileged) port, if the value is zero the default will be to
5055bd9f8f1Srg137905 * use non-reserved ports. Users of kRPC may override this by using
5065bd9f8f1Srg137905 * CLNT_CONTROL() and CLSET_BINDRESVPORT.
5075bd9f8f1Srg137905 */
50881dbf0b5SDai Ngo int clnt_cots_do_bindresvport = 1;
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate static zone_key_t zone_cots_key;
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate /*
5132081ac19SDai Ngo * Defaults TCP send and receive buffer size for RPC connections.
5142081ac19SDai Ngo * These values can be tuned by /etc/system.
5152081ac19SDai Ngo */
5162081ac19SDai Ngo int rpc_send_bufsz = 1024*1024;
5172081ac19SDai Ngo int rpc_recv_bufsz = 1024*1024;
5182081ac19SDai Ngo /*
5192081ac19SDai Ngo * To use system-wide default for TCP send and receive buffer size,
5202081ac19SDai Ngo * use /etc/system to set rpc_default_tcp_bufsz to 1:
5212081ac19SDai Ngo *
5222081ac19SDai Ngo * set rpcmod:rpc_default_tcp_bufsz=1
5232081ac19SDai Ngo */
5242081ac19SDai Ngo int rpc_default_tcp_bufsz = 0;
5252081ac19SDai Ngo
5262081ac19SDai Ngo /*
5277c478bd9Sstevel@tonic-gate * We need to do this after all kernel threads in the zone have exited.
5287c478bd9Sstevel@tonic-gate */
5297c478bd9Sstevel@tonic-gate /* ARGSUSED */
5307c478bd9Sstevel@tonic-gate static void
clnt_zone_destroy(zoneid_t zoneid,void * unused)5317c478bd9Sstevel@tonic-gate clnt_zone_destroy(zoneid_t zoneid, void *unused)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate struct cm_xprt **cmp;
5347c478bd9Sstevel@tonic-gate struct cm_xprt *cm_entry;
5357c478bd9Sstevel@tonic-gate struct cm_xprt *freelist = NULL;
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate mutex_enter(&connmgr_lock);
5387c478bd9Sstevel@tonic-gate cmp = &cm_hd;
5397c478bd9Sstevel@tonic-gate while ((cm_entry = *cmp) != NULL) {
5407c478bd9Sstevel@tonic-gate if (cm_entry->x_zoneid == zoneid) {
5417c478bd9Sstevel@tonic-gate *cmp = cm_entry->x_next;
5427c478bd9Sstevel@tonic-gate cm_entry->x_next = freelist;
5437c478bd9Sstevel@tonic-gate freelist = cm_entry;
5447c478bd9Sstevel@tonic-gate } else {
5457c478bd9Sstevel@tonic-gate cmp = &cm_entry->x_next;
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
5497c478bd9Sstevel@tonic-gate while ((cm_entry = freelist) != NULL) {
5507c478bd9Sstevel@tonic-gate freelist = cm_entry->x_next;
5517c478bd9Sstevel@tonic-gate connmgr_close(cm_entry);
5527c478bd9Sstevel@tonic-gate }
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate int
clnt_cots_kcreate(dev_t dev,struct netbuf * addr,int family,rpcprog_t prog,rpcvers_t vers,uint_t max_msgsize,cred_t * cred,CLIENT ** ncl)5567c478bd9Sstevel@tonic-gate clnt_cots_kcreate(dev_t dev, struct netbuf *addr, int family, rpcprog_t prog,
5577c478bd9Sstevel@tonic-gate rpcvers_t vers, uint_t max_msgsize, cred_t *cred, CLIENT **ncl)
5587c478bd9Sstevel@tonic-gate {
5597c478bd9Sstevel@tonic-gate CLIENT *h;
5607c478bd9Sstevel@tonic-gate cku_private_t *p;
5617c478bd9Sstevel@tonic-gate struct rpc_msg call_msg;
5627c478bd9Sstevel@tonic-gate struct rpcstat *rpcstat;
5637c478bd9Sstevel@tonic-gate
5647c478bd9Sstevel@tonic-gate RPCLOG(8, "clnt_cots_kcreate: prog %u\n", prog);
5657c478bd9Sstevel@tonic-gate
566108322fbScarlsonj rpcstat = zone_getspecific(rpcstat_zone_key, rpc_zone());
5677c478bd9Sstevel@tonic-gate ASSERT(rpcstat != NULL);
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate /* Allocate and intialize the client handle. */
5707c478bd9Sstevel@tonic-gate p = kmem_zalloc(sizeof (*p), KM_SLEEP);
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate h = ptoh(p);
5737c478bd9Sstevel@tonic-gate
5747c478bd9Sstevel@tonic-gate h->cl_private = (caddr_t)p;
5757c478bd9Sstevel@tonic-gate h->cl_auth = authkern_create();
5767c478bd9Sstevel@tonic-gate h->cl_ops = &tcp_ops;
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate cv_init(&p->cku_call.call_cv, NULL, CV_DEFAULT, NULL);
5797c478bd9Sstevel@tonic-gate mutex_init(&p->cku_call.call_lock, NULL, MUTEX_DEFAULT, NULL);
5807c478bd9Sstevel@tonic-gate
5817c478bd9Sstevel@tonic-gate /*
5827c478bd9Sstevel@tonic-gate * If the current sanity check size in rpcmod is smaller
5837c478bd9Sstevel@tonic-gate * than the size needed, then increase the sanity check.
5847c478bd9Sstevel@tonic-gate */
5857c478bd9Sstevel@tonic-gate if (max_msgsize != 0 && clnt_max_msg_sizep != NULL &&
5867c478bd9Sstevel@tonic-gate max_msgsize > *clnt_max_msg_sizep) {
5877c478bd9Sstevel@tonic-gate mutex_enter(&clnt_max_msg_lock);
5887c478bd9Sstevel@tonic-gate if (max_msgsize > *clnt_max_msg_sizep)
5897c478bd9Sstevel@tonic-gate *clnt_max_msg_sizep = max_msgsize;
5907c478bd9Sstevel@tonic-gate mutex_exit(&clnt_max_msg_lock);
5917c478bd9Sstevel@tonic-gate }
5927c478bd9Sstevel@tonic-gate
5937c478bd9Sstevel@tonic-gate p->cku_outbuflen = COTS_DEFAULT_ALLOCSIZE;
5947c478bd9Sstevel@tonic-gate
5957c478bd9Sstevel@tonic-gate /* Preserialize the call message header */
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate call_msg.rm_xid = 0;
5987c478bd9Sstevel@tonic-gate call_msg.rm_direction = CALL;
5997c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
6007c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_prog = prog;
6017c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_vers = vers;
6027c478bd9Sstevel@tonic-gate
6037c478bd9Sstevel@tonic-gate xdrmem_create(&p->cku_outxdr, p->cku_rpchdr, WIRE_HDR_SIZE, XDR_ENCODE);
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate if (!xdr_callhdr(&p->cku_outxdr, &call_msg)) {
6067c478bd9Sstevel@tonic-gate RPCLOG0(1, "clnt_cots_kcreate - Fatal header serialization "
6077c478bd9Sstevel@tonic-gate "error\n");
6087c478bd9Sstevel@tonic-gate auth_destroy(h->cl_auth);
6097c478bd9Sstevel@tonic-gate kmem_free(p, sizeof (cku_private_t));
6107c478bd9Sstevel@tonic-gate RPCLOG0(1, "clnt_cots_kcreate: create failed error EINVAL\n");
6117c478bd9Sstevel@tonic-gate return (EINVAL); /* XXX */
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate
6147c478bd9Sstevel@tonic-gate /*
6157c478bd9Sstevel@tonic-gate * The zalloc initialized the fields below.
6167c478bd9Sstevel@tonic-gate * p->cku_xid = 0;
6177c478bd9Sstevel@tonic-gate * p->cku_flags = 0;
6187c478bd9Sstevel@tonic-gate * p->cku_srcaddr.len = 0;
6197c478bd9Sstevel@tonic-gate * p->cku_srcaddr.maxlen = 0;
6207c478bd9Sstevel@tonic-gate */
6217c478bd9Sstevel@tonic-gate
6227c478bd9Sstevel@tonic-gate p->cku_cred = cred;
6237c478bd9Sstevel@tonic-gate p->cku_device = dev;
6247c478bd9Sstevel@tonic-gate p->cku_addrfmly = family;
6257c478bd9Sstevel@tonic-gate p->cku_addr.buf = kmem_zalloc(addr->maxlen, KM_SLEEP);
6267c478bd9Sstevel@tonic-gate p->cku_addr.maxlen = addr->maxlen;
6277c478bd9Sstevel@tonic-gate p->cku_addr.len = addr->len;
6287c478bd9Sstevel@tonic-gate bcopy(addr->buf, p->cku_addr.buf, addr->len);
6297c478bd9Sstevel@tonic-gate p->cku_stats = rpcstat->rpc_cots_client;
6307c478bd9Sstevel@tonic-gate p->cku_useresvport = -1; /* value is has not been set */
6317c478bd9Sstevel@tonic-gate
6327c478bd9Sstevel@tonic-gate *ncl = h;
6337c478bd9Sstevel@tonic-gate return (0);
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6377c478bd9Sstevel@tonic-gate static void
clnt_cots_kabort(CLIENT * h)6387c478bd9Sstevel@tonic-gate clnt_cots_kabort(CLIENT *h)
6397c478bd9Sstevel@tonic-gate {
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate
6427c478bd9Sstevel@tonic-gate /*
6437c478bd9Sstevel@tonic-gate * Return error info on this handle.
6447c478bd9Sstevel@tonic-gate */
6457c478bd9Sstevel@tonic-gate static void
clnt_cots_kerror(CLIENT * h,struct rpc_err * err)6467c478bd9Sstevel@tonic-gate clnt_cots_kerror(CLIENT *h, struct rpc_err *err)
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
6497c478bd9Sstevel@tonic-gate cku_private_t *p = htop(h);
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate *err = p->cku_err;
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate static bool_t
clnt_cots_kfreeres(CLIENT * h,xdrproc_t xdr_res,caddr_t res_ptr)6557c478bd9Sstevel@tonic-gate clnt_cots_kfreeres(CLIENT *h, xdrproc_t xdr_res, caddr_t res_ptr)
6567c478bd9Sstevel@tonic-gate {
6577c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
6587c478bd9Sstevel@tonic-gate cku_private_t *p = htop(h);
6597c478bd9Sstevel@tonic-gate XDR *xdrs;
6607c478bd9Sstevel@tonic-gate
6617c478bd9Sstevel@tonic-gate xdrs = &(p->cku_outxdr);
6627c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_FREE;
6637c478bd9Sstevel@tonic-gate return ((*xdr_res)(xdrs, res_ptr));
6647c478bd9Sstevel@tonic-gate }
6657c478bd9Sstevel@tonic-gate
6667c478bd9Sstevel@tonic-gate static bool_t
clnt_cots_kcontrol(CLIENT * h,int cmd,char * arg)6677c478bd9Sstevel@tonic-gate clnt_cots_kcontrol(CLIENT *h, int cmd, char *arg)
6687c478bd9Sstevel@tonic-gate {
6697c478bd9Sstevel@tonic-gate cku_private_t *p = htop(h);
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate switch (cmd) {
6727c478bd9Sstevel@tonic-gate case CLSET_PROGRESS:
6737c478bd9Sstevel@tonic-gate p->cku_progress = TRUE;
6747c478bd9Sstevel@tonic-gate return (TRUE);
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate case CLSET_XID:
6777c478bd9Sstevel@tonic-gate if (arg == NULL)
6787c478bd9Sstevel@tonic-gate return (FALSE);
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate p->cku_xid = *((uint32_t *)arg);
6817c478bd9Sstevel@tonic-gate return (TRUE);
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate case CLGET_XID:
6847c478bd9Sstevel@tonic-gate if (arg == NULL)
6857c478bd9Sstevel@tonic-gate return (FALSE);
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate *((uint32_t *)arg) = p->cku_xid;
6887c478bd9Sstevel@tonic-gate return (TRUE);
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate case CLSET_NODELAYONERR:
6917c478bd9Sstevel@tonic-gate if (arg == NULL)
6927c478bd9Sstevel@tonic-gate return (FALSE);
6937c478bd9Sstevel@tonic-gate
6947c478bd9Sstevel@tonic-gate if (*((bool_t *)arg) == TRUE) {
6957c478bd9Sstevel@tonic-gate p->cku_nodelayonerr = TRUE;
6967c478bd9Sstevel@tonic-gate return (TRUE);
6977c478bd9Sstevel@tonic-gate }
6987c478bd9Sstevel@tonic-gate if (*((bool_t *)arg) == FALSE) {
6997c478bd9Sstevel@tonic-gate p->cku_nodelayonerr = FALSE;
7007c478bd9Sstevel@tonic-gate return (TRUE);
7017c478bd9Sstevel@tonic-gate }
7027c478bd9Sstevel@tonic-gate return (FALSE);
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate case CLGET_NODELAYONERR:
7057c478bd9Sstevel@tonic-gate if (arg == NULL)
7067c478bd9Sstevel@tonic-gate return (FALSE);
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate *((bool_t *)arg) = p->cku_nodelayonerr;
7097c478bd9Sstevel@tonic-gate return (TRUE);
7107c478bd9Sstevel@tonic-gate
7117c478bd9Sstevel@tonic-gate case CLSET_BINDRESVPORT:
7127c478bd9Sstevel@tonic-gate if (arg == NULL)
7137c478bd9Sstevel@tonic-gate return (FALSE);
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate if (*(int *)arg != 1 && *(int *)arg != 0)
7167c478bd9Sstevel@tonic-gate return (FALSE);
7177c478bd9Sstevel@tonic-gate
7187c478bd9Sstevel@tonic-gate p->cku_useresvport = *(int *)arg;
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate return (TRUE);
7217c478bd9Sstevel@tonic-gate
7227c478bd9Sstevel@tonic-gate case CLGET_BINDRESVPORT:
7237c478bd9Sstevel@tonic-gate if (arg == NULL)
7247c478bd9Sstevel@tonic-gate return (FALSE);
7257c478bd9Sstevel@tonic-gate
7267c478bd9Sstevel@tonic-gate *(int *)arg = p->cku_useresvport;
7277c478bd9Sstevel@tonic-gate
7287c478bd9Sstevel@tonic-gate return (TRUE);
7297c478bd9Sstevel@tonic-gate
7307c478bd9Sstevel@tonic-gate default:
7317c478bd9Sstevel@tonic-gate return (FALSE);
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate /*
7367c478bd9Sstevel@tonic-gate * Destroy rpc handle. Frees the space used for output buffer,
7377c478bd9Sstevel@tonic-gate * private data, and handle structure.
7387c478bd9Sstevel@tonic-gate */
7397c478bd9Sstevel@tonic-gate static void
clnt_cots_kdestroy(CLIENT * h)7407c478bd9Sstevel@tonic-gate clnt_cots_kdestroy(CLIENT *h)
7417c478bd9Sstevel@tonic-gate {
7427c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
7437c478bd9Sstevel@tonic-gate cku_private_t *p = htop(h);
7447c478bd9Sstevel@tonic-gate calllist_t *call = &p->cku_call;
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate RPCLOG(8, "clnt_cots_kdestroy h: %p\n", (void *)h);
7477c478bd9Sstevel@tonic-gate RPCLOG(8, "clnt_cots_kdestroy h: xid=0x%x\n", p->cku_xid);
7487c478bd9Sstevel@tonic-gate
7497c478bd9Sstevel@tonic-gate if (p->cku_flags & CKU_ONQUEUE) {
7507c478bd9Sstevel@tonic-gate RPCLOG(64, "clnt_cots_kdestroy h: removing call for xid 0x%x "
7517c478bd9Sstevel@tonic-gate "from dispatch list\n", p->cku_xid);
7527c478bd9Sstevel@tonic-gate call_table_remove(call);
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate if (call->call_reply)
7567c478bd9Sstevel@tonic-gate freemsg(call->call_reply);
7577c478bd9Sstevel@tonic-gate cv_destroy(&call->call_cv);
7587c478bd9Sstevel@tonic-gate mutex_destroy(&call->call_lock);
7597c478bd9Sstevel@tonic-gate
7607c478bd9Sstevel@tonic-gate kmem_free(p->cku_srcaddr.buf, p->cku_srcaddr.maxlen);
7617c478bd9Sstevel@tonic-gate kmem_free(p->cku_addr.buf, p->cku_addr.maxlen);
7627c478bd9Sstevel@tonic-gate kmem_free(p, sizeof (*p));
7637c478bd9Sstevel@tonic-gate }
7647c478bd9Sstevel@tonic-gate
7657c478bd9Sstevel@tonic-gate static int clnt_cots_pulls;
7667c478bd9Sstevel@tonic-gate #define RM_HDR_SIZE 4 /* record mark header size */
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate /*
7697c478bd9Sstevel@tonic-gate * Call remote procedure.
7707c478bd9Sstevel@tonic-gate */
7717c478bd9Sstevel@tonic-gate static enum clnt_stat
clnt_cots_kcallit(CLIENT * h,rpcproc_t procnum,xdrproc_t xdr_args,caddr_t argsp,xdrproc_t xdr_results,caddr_t resultsp,struct timeval wait)7727c478bd9Sstevel@tonic-gate clnt_cots_kcallit(CLIENT *h, rpcproc_t procnum, xdrproc_t xdr_args,
7737c478bd9Sstevel@tonic-gate caddr_t argsp, xdrproc_t xdr_results, caddr_t resultsp, struct timeval wait)
7747c478bd9Sstevel@tonic-gate {
7757c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
7767c478bd9Sstevel@tonic-gate cku_private_t *p = htop(h);
7777c478bd9Sstevel@tonic-gate calllist_t *call = &p->cku_call;
7787c478bd9Sstevel@tonic-gate XDR *xdrs;
7797c478bd9Sstevel@tonic-gate struct rpc_msg reply_msg;
7807c478bd9Sstevel@tonic-gate mblk_t *mp;
7817c478bd9Sstevel@tonic-gate #ifdef RPCDEBUG
7827c478bd9Sstevel@tonic-gate clock_t time_sent;
7837c478bd9Sstevel@tonic-gate #endif
7847c478bd9Sstevel@tonic-gate struct netbuf *retryaddr;
7857c478bd9Sstevel@tonic-gate struct cm_xprt *cm_entry = NULL;
7867c478bd9Sstevel@tonic-gate queue_t *wq;
787e280ed37SDai Ngo int len, waitsecs, max_waitsecs;
7887c478bd9Sstevel@tonic-gate int mpsize;
7897c478bd9Sstevel@tonic-gate int refreshes = REFRESHES;
7907c478bd9Sstevel@tonic-gate int interrupted;
7917c478bd9Sstevel@tonic-gate int tidu_size;
7927c478bd9Sstevel@tonic-gate enum clnt_stat status;
7937c478bd9Sstevel@tonic-gate struct timeval cwait;
7947c478bd9Sstevel@tonic-gate bool_t delay_first = FALSE;
795d3d50737SRafael Vanoni clock_t ticks, now;
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate RPCLOG(2, "clnt_cots_kcallit, procnum %u\n", procnum);
7987c478bd9Sstevel@tonic-gate COTSRCSTAT_INCR(p->cku_stats, rccalls);
7997c478bd9Sstevel@tonic-gate
8007c478bd9Sstevel@tonic-gate RPCLOG(2, "clnt_cots_kcallit: wait.tv_sec: %ld\n", wait.tv_sec);
8017c478bd9Sstevel@tonic-gate RPCLOG(2, "clnt_cots_kcallit: wait.tv_usec: %ld\n", wait.tv_usec);
8027c478bd9Sstevel@tonic-gate /*
8037c478bd9Sstevel@tonic-gate * Bug ID 1240234:
8047c478bd9Sstevel@tonic-gate * Look out for zero length timeouts. We don't want to
8057c478bd9Sstevel@tonic-gate * wait zero seconds for a connection to be established.
8067c478bd9Sstevel@tonic-gate */
8077c478bd9Sstevel@tonic-gate if (wait.tv_sec < clnt_cots_min_conntout) {
8087c478bd9Sstevel@tonic-gate cwait.tv_sec = clnt_cots_min_conntout;
8097c478bd9Sstevel@tonic-gate cwait.tv_usec = 0;
8107c478bd9Sstevel@tonic-gate RPCLOG(8, "clnt_cots_kcallit: wait.tv_sec (%ld) too low,",
8117c478bd9Sstevel@tonic-gate wait.tv_sec);
8127c478bd9Sstevel@tonic-gate RPCLOG(8, " setting to: %d\n", clnt_cots_min_conntout);
8137c478bd9Sstevel@tonic-gate } else {
8147c478bd9Sstevel@tonic-gate cwait = wait;
8157c478bd9Sstevel@tonic-gate }
8167c478bd9Sstevel@tonic-gate
8177c478bd9Sstevel@tonic-gate call_again:
8187c478bd9Sstevel@tonic-gate if (cm_entry) {
8197c478bd9Sstevel@tonic-gate connmgr_release(cm_entry);
8207c478bd9Sstevel@tonic-gate cm_entry = NULL;
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate mp = NULL;
8247c478bd9Sstevel@tonic-gate
8257c478bd9Sstevel@tonic-gate /*
8267c478bd9Sstevel@tonic-gate * If the call is not a retry, allocate a new xid and cache it
8277c478bd9Sstevel@tonic-gate * for future retries.
8287c478bd9Sstevel@tonic-gate * Bug ID 1246045:
8297c478bd9Sstevel@tonic-gate * Treat call as a retry for purposes of binding the source
8307c478bd9Sstevel@tonic-gate * port only if we actually attempted to send anything on
8317c478bd9Sstevel@tonic-gate * the previous call.
8327c478bd9Sstevel@tonic-gate */
8337c478bd9Sstevel@tonic-gate if (p->cku_xid == 0) {
8347c478bd9Sstevel@tonic-gate p->cku_xid = alloc_xid();
8358ffff9fdSgt29601 call->call_zoneid = rpc_zoneid();
8368ffff9fdSgt29601
8377c478bd9Sstevel@tonic-gate /*
8387c478bd9Sstevel@tonic-gate * We need to ASSERT here that our xid != 0 because this
8397c478bd9Sstevel@tonic-gate * determines whether or not our call record gets placed on
8407c478bd9Sstevel@tonic-gate * the hash table or the linked list. By design, we mandate
8417c478bd9Sstevel@tonic-gate * that RPC calls over cots must have xid's != 0, so we can
8427c478bd9Sstevel@tonic-gate * ensure proper management of the hash table.
8437c478bd9Sstevel@tonic-gate */
8447c478bd9Sstevel@tonic-gate ASSERT(p->cku_xid != 0);
8457c478bd9Sstevel@tonic-gate
8467c478bd9Sstevel@tonic-gate retryaddr = NULL;
8477c478bd9Sstevel@tonic-gate p->cku_flags &= ~CKU_SENT;
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate if (p->cku_flags & CKU_ONQUEUE) {
8507c478bd9Sstevel@tonic-gate RPCLOG(8, "clnt_cots_kcallit: new call, dequeuing old"
8517c478bd9Sstevel@tonic-gate " one (%p)\n", (void *)call);
8527c478bd9Sstevel@tonic-gate call_table_remove(call);
8537c478bd9Sstevel@tonic-gate p->cku_flags &= ~CKU_ONQUEUE;
8547c478bd9Sstevel@tonic-gate RPCLOG(64, "clnt_cots_kcallit: removing call from "
8557c478bd9Sstevel@tonic-gate "dispatch list because xid was zero (now 0x%x)\n",
8567c478bd9Sstevel@tonic-gate p->cku_xid);
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate if (call->call_reply != NULL) {
8607c478bd9Sstevel@tonic-gate freemsg(call->call_reply);
8617c478bd9Sstevel@tonic-gate call->call_reply = NULL;
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate } else if (p->cku_srcaddr.buf == NULL || p->cku_srcaddr.len == 0) {
8647c478bd9Sstevel@tonic-gate retryaddr = NULL;
8657c478bd9Sstevel@tonic-gate
8667c478bd9Sstevel@tonic-gate } else if (p->cku_flags & CKU_SENT) {
8677c478bd9Sstevel@tonic-gate retryaddr = &p->cku_srcaddr;
8687c478bd9Sstevel@tonic-gate
8697c478bd9Sstevel@tonic-gate } else {
8707c478bd9Sstevel@tonic-gate /*
8717c478bd9Sstevel@tonic-gate * Bug ID 1246045: Nothing was sent, so set retryaddr to
8727c478bd9Sstevel@tonic-gate * NULL and let connmgr_get() bind to any source port it
8737c478bd9Sstevel@tonic-gate * can get.
8747c478bd9Sstevel@tonic-gate */
8757c478bd9Sstevel@tonic-gate retryaddr = NULL;
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate RPCLOG(64, "clnt_cots_kcallit: xid = 0x%x", p->cku_xid);
8797c478bd9Sstevel@tonic-gate RPCLOG(64, " flags = 0x%x\n", p->cku_flags);
8807c478bd9Sstevel@tonic-gate
8817c478bd9Sstevel@tonic-gate p->cku_err.re_status = RPC_TIMEDOUT;
8827c478bd9Sstevel@tonic-gate p->cku_err.re_errno = p->cku_err.re_terrno = 0;
8837c478bd9Sstevel@tonic-gate
8847c478bd9Sstevel@tonic-gate cm_entry = connmgr_wrapget(retryaddr, &cwait, p);
8857c478bd9Sstevel@tonic-gate
8867c478bd9Sstevel@tonic-gate if (cm_entry == NULL) {
8877c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_cots_kcallit: can't connect status %s\n",
8887c478bd9Sstevel@tonic-gate clnt_sperrno(p->cku_err.re_status));
8897c478bd9Sstevel@tonic-gate
8907c478bd9Sstevel@tonic-gate /*
8917c478bd9Sstevel@tonic-gate * The reasons why we fail to create a connection are
8927c478bd9Sstevel@tonic-gate * varied. In most cases we don't want the caller to
8937c478bd9Sstevel@tonic-gate * immediately retry. This could have one or more
8947c478bd9Sstevel@tonic-gate * bad effects. This includes flooding the net with
8957c478bd9Sstevel@tonic-gate * connect requests to ports with no listener; a hard
8967c478bd9Sstevel@tonic-gate * kernel loop due to all the "reserved" TCP ports being
8977c478bd9Sstevel@tonic-gate * in use.
8987c478bd9Sstevel@tonic-gate */
8997c478bd9Sstevel@tonic-gate delay_first = TRUE;
9007c478bd9Sstevel@tonic-gate
9017c478bd9Sstevel@tonic-gate /*
9027c478bd9Sstevel@tonic-gate * Even if we end up returning EINTR, we still count a
9037c478bd9Sstevel@tonic-gate * a "can't connect", because the connection manager
9047c478bd9Sstevel@tonic-gate * might have been committed to waiting for or timing out on
9057c478bd9Sstevel@tonic-gate * a connection.
9067c478bd9Sstevel@tonic-gate */
9077c478bd9Sstevel@tonic-gate COTSRCSTAT_INCR(p->cku_stats, rccantconn);
9087c478bd9Sstevel@tonic-gate switch (p->cku_err.re_status) {
9097c478bd9Sstevel@tonic-gate case RPC_INTR:
9107c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EINTR;
9117c478bd9Sstevel@tonic-gate
9127c478bd9Sstevel@tonic-gate /*
9137c478bd9Sstevel@tonic-gate * No need to delay because a UNIX signal(2)
9147c478bd9Sstevel@tonic-gate * interrupted us. The caller likely won't
9157c478bd9Sstevel@tonic-gate * retry the CLNT_CALL() and even if it does,
9167c478bd9Sstevel@tonic-gate * we assume the caller knows what it is doing.
9177c478bd9Sstevel@tonic-gate */
9187c478bd9Sstevel@tonic-gate delay_first = FALSE;
9197c478bd9Sstevel@tonic-gate break;
9207c478bd9Sstevel@tonic-gate
9217c478bd9Sstevel@tonic-gate case RPC_TIMEDOUT:
9227c478bd9Sstevel@tonic-gate p->cku_err.re_errno = ETIMEDOUT;
9237c478bd9Sstevel@tonic-gate
9247c478bd9Sstevel@tonic-gate /*
9257c478bd9Sstevel@tonic-gate * No need to delay because timed out already
9267c478bd9Sstevel@tonic-gate * on the connection request and assume that the
9277c478bd9Sstevel@tonic-gate * transport time out is longer than our minimum
9287c478bd9Sstevel@tonic-gate * timeout, or least not too much smaller.
9297c478bd9Sstevel@tonic-gate */
9307c478bd9Sstevel@tonic-gate delay_first = FALSE;
9317c478bd9Sstevel@tonic-gate break;
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate case RPC_SYSTEMERROR:
9347c478bd9Sstevel@tonic-gate case RPC_TLIERROR:
9357c478bd9Sstevel@tonic-gate /*
9367c478bd9Sstevel@tonic-gate * We want to delay here because a transient
9377c478bd9Sstevel@tonic-gate * system error has a better chance of going away
9387c478bd9Sstevel@tonic-gate * if we delay a bit. If it's not transient, then
9397c478bd9Sstevel@tonic-gate * we don't want end up in a hard kernel loop
9407c478bd9Sstevel@tonic-gate * due to retries.
9417c478bd9Sstevel@tonic-gate */
9427c478bd9Sstevel@tonic-gate ASSERT(p->cku_err.re_errno != 0);
9437c478bd9Sstevel@tonic-gate break;
9447c478bd9Sstevel@tonic-gate
9457c478bd9Sstevel@tonic-gate
9467c478bd9Sstevel@tonic-gate case RPC_CANTCONNECT:
9477c478bd9Sstevel@tonic-gate /*
9487c478bd9Sstevel@tonic-gate * RPC_CANTCONNECT is set on T_ERROR_ACK which
9497c478bd9Sstevel@tonic-gate * implies some error down in the TCP layer or
9507c478bd9Sstevel@tonic-gate * below. If cku_nodelayonerror is set then we
9517c478bd9Sstevel@tonic-gate * assume the caller knows not to try too hard.
9527c478bd9Sstevel@tonic-gate */
9537c478bd9Sstevel@tonic-gate RPCLOG0(8, "clnt_cots_kcallit: connection failed,");
9547c478bd9Sstevel@tonic-gate RPCLOG0(8, " re_status=RPC_CANTCONNECT,");
9557c478bd9Sstevel@tonic-gate RPCLOG(8, " re_errno=%d,", p->cku_err.re_errno);
9567c478bd9Sstevel@tonic-gate RPCLOG(8, " cku_nodelayonerr=%d", p->cku_nodelayonerr);
9577c478bd9Sstevel@tonic-gate if (p->cku_nodelayonerr == TRUE)
9587c478bd9Sstevel@tonic-gate delay_first = FALSE;
9597c478bd9Sstevel@tonic-gate
9607c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EIO;
9617c478bd9Sstevel@tonic-gate
9627c478bd9Sstevel@tonic-gate break;
9637c478bd9Sstevel@tonic-gate
9647c478bd9Sstevel@tonic-gate case RPC_XPRTFAILED:
9657c478bd9Sstevel@tonic-gate /*
9667c478bd9Sstevel@tonic-gate * We want to delay here because we likely
9677c478bd9Sstevel@tonic-gate * got a refused connection.
9687c478bd9Sstevel@tonic-gate */
969af41c4bfSvv149972 if (p->cku_err.re_errno == 0)
970af41c4bfSvv149972 p->cku_err.re_errno = EIO;
9717c478bd9Sstevel@tonic-gate
972af41c4bfSvv149972 RPCLOG(1, "clnt_cots_kcallit: transport failed: %d\n",
973af41c4bfSvv149972 p->cku_err.re_errno);
974af41c4bfSvv149972
975af41c4bfSvv149972 break;
9767c478bd9Sstevel@tonic-gate
9777c478bd9Sstevel@tonic-gate default:
9787c478bd9Sstevel@tonic-gate /*
9797c478bd9Sstevel@tonic-gate * We delay here because it is better to err
9807c478bd9Sstevel@tonic-gate * on the side of caution. If we got here then
9817c478bd9Sstevel@tonic-gate * status could have been RPC_SUCCESS, but we
9827c478bd9Sstevel@tonic-gate * know that we did not get a connection, so
9837c478bd9Sstevel@tonic-gate * force the rpc status to RPC_CANTCONNECT.
9847c478bd9Sstevel@tonic-gate */
9857c478bd9Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTCONNECT;
9867c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EIO;
9877c478bd9Sstevel@tonic-gate break;
9887c478bd9Sstevel@tonic-gate }
9897c478bd9Sstevel@tonic-gate if (delay_first == TRUE)
9907c478bd9Sstevel@tonic-gate ticks = clnt_cots_min_tout * drv_usectohz(1000000);
9917c478bd9Sstevel@tonic-gate goto cots_done;
9927c478bd9Sstevel@tonic-gate }
9937c478bd9Sstevel@tonic-gate
9947c478bd9Sstevel@tonic-gate /*
9957c478bd9Sstevel@tonic-gate * If we've never sent any request on this connection (send count
9967c478bd9Sstevel@tonic-gate * is zero, or the connection has been reset), cache the
9977c478bd9Sstevel@tonic-gate * the connection's create time and send a request (possibly a retry)
9987c478bd9Sstevel@tonic-gate */
9997c478bd9Sstevel@tonic-gate if ((p->cku_flags & CKU_SENT) == 0 ||
10007c478bd9Sstevel@tonic-gate p->cku_ctime != cm_entry->x_ctime) {
10017c478bd9Sstevel@tonic-gate p->cku_ctime = cm_entry->x_ctime;
10027c478bd9Sstevel@tonic-gate
10037c478bd9Sstevel@tonic-gate } else if ((p->cku_flags & CKU_SENT) && (p->cku_flags & CKU_ONQUEUE) &&
10047c478bd9Sstevel@tonic-gate (call->call_reply != NULL ||
10057c478bd9Sstevel@tonic-gate p->cku_recv_attempts < clnt_cots_maxrecv)) {
10067c478bd9Sstevel@tonic-gate
10077c478bd9Sstevel@tonic-gate /*
10087c478bd9Sstevel@tonic-gate * If we've sent a request and our call is on the dispatch
10097c478bd9Sstevel@tonic-gate * queue and we haven't made too many receive attempts, then
10107c478bd9Sstevel@tonic-gate * don't re-send, just receive.
10117c478bd9Sstevel@tonic-gate */
10127c478bd9Sstevel@tonic-gate p->cku_recv_attempts++;
10137c478bd9Sstevel@tonic-gate goto read_again;
10147c478bd9Sstevel@tonic-gate }
10157c478bd9Sstevel@tonic-gate
10167c478bd9Sstevel@tonic-gate /*
10177c478bd9Sstevel@tonic-gate * Now we create the RPC request in a STREAMS message. We have to do
10187c478bd9Sstevel@tonic-gate * this after the call to connmgr_get so that we have the correct
10197c478bd9Sstevel@tonic-gate * TIDU size for the transport.
10207c478bd9Sstevel@tonic-gate */
10217c478bd9Sstevel@tonic-gate tidu_size = cm_entry->x_tidu_size;
10227c478bd9Sstevel@tonic-gate len = MSG_OFFSET + MAX(tidu_size, RM_HDR_SIZE + WIRE_HDR_SIZE);
10237c478bd9Sstevel@tonic-gate
10247c478bd9Sstevel@tonic-gate while ((mp = allocb(len, BPRI_MED)) == NULL) {
10257c478bd9Sstevel@tonic-gate if (strwaitbuf(len, BPRI_MED)) {
10267c478bd9Sstevel@tonic-gate p->cku_err.re_status = RPC_SYSTEMERROR;
10277c478bd9Sstevel@tonic-gate p->cku_err.re_errno = ENOSR;
10287c478bd9Sstevel@tonic-gate COTSRCSTAT_INCR(p->cku_stats, rcnomem);
10297c478bd9Sstevel@tonic-gate goto cots_done;
10307c478bd9Sstevel@tonic-gate }
10317c478bd9Sstevel@tonic-gate }
10327c478bd9Sstevel@tonic-gate xdrs = &p->cku_outxdr;
10337c478bd9Sstevel@tonic-gate xdrmblk_init(xdrs, mp, XDR_ENCODE, tidu_size);
10347c478bd9Sstevel@tonic-gate mpsize = MBLKSIZE(mp);
10357c478bd9Sstevel@tonic-gate ASSERT(mpsize >= len);
10367c478bd9Sstevel@tonic-gate ASSERT(mp->b_rptr == mp->b_datap->db_base);
10377c478bd9Sstevel@tonic-gate
10387c478bd9Sstevel@tonic-gate /*
10397c478bd9Sstevel@tonic-gate * If the size of mblk is not appreciably larger than what we
10407c478bd9Sstevel@tonic-gate * asked, then resize the mblk to exactly len bytes. The reason for
10417c478bd9Sstevel@tonic-gate * this: suppose len is 1600 bytes, the tidu is 1460 bytes
10427c478bd9Sstevel@tonic-gate * (from TCP over ethernet), and the arguments to the RPC require
10437c478bd9Sstevel@tonic-gate * 2800 bytes. Ideally we want the protocol to render two
10447c478bd9Sstevel@tonic-gate * ~1400 byte segments over the wire. However if allocb() gives us a 2k
10457c478bd9Sstevel@tonic-gate * mblk, and we allocate a second mblk for the remainder, the protocol
10467c478bd9Sstevel@tonic-gate * module may generate 3 segments over the wire:
10477c478bd9Sstevel@tonic-gate * 1460 bytes for the first, 448 (2048 - 1600) for the second, and
10487c478bd9Sstevel@tonic-gate * 892 for the third. If we "waste" 448 bytes in the first mblk,
10497c478bd9Sstevel@tonic-gate * the XDR encoding will generate two ~1400 byte mblks, and the
10507c478bd9Sstevel@tonic-gate * protocol module is more likely to produce properly sized segments.
10517c478bd9Sstevel@tonic-gate */
10527c478bd9Sstevel@tonic-gate if ((mpsize >> 1) <= len)
10537c478bd9Sstevel@tonic-gate mp->b_rptr += (mpsize - len);
10547c478bd9Sstevel@tonic-gate
10557c478bd9Sstevel@tonic-gate /*
10567c478bd9Sstevel@tonic-gate * Adjust b_rptr to reserve space for the non-data protocol headers
10577c478bd9Sstevel@tonic-gate * any downstream modules might like to add, and for the
10587c478bd9Sstevel@tonic-gate * record marking header.
10597c478bd9Sstevel@tonic-gate */
10607c478bd9Sstevel@tonic-gate mp->b_rptr += (MSG_OFFSET + RM_HDR_SIZE);
10617c478bd9Sstevel@tonic-gate
10627c478bd9Sstevel@tonic-gate if (h->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
10637c478bd9Sstevel@tonic-gate /* Copy in the preserialized RPC header information. */
10647c478bd9Sstevel@tonic-gate bcopy(p->cku_rpchdr, mp->b_rptr, WIRE_HDR_SIZE);
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate /* Use XDR_SETPOS() to set the b_wptr to past the RPC header. */
10677c478bd9Sstevel@tonic-gate XDR_SETPOS(xdrs, (uint_t)(mp->b_rptr - mp->b_datap->db_base +
10687c478bd9Sstevel@tonic-gate WIRE_HDR_SIZE));
10697c478bd9Sstevel@tonic-gate
10707c478bd9Sstevel@tonic-gate ASSERT((mp->b_wptr - mp->b_rptr) == WIRE_HDR_SIZE);
10717c478bd9Sstevel@tonic-gate
10727c478bd9Sstevel@tonic-gate /* Serialize the procedure number and the arguments. */
10737c478bd9Sstevel@tonic-gate if ((!XDR_PUTINT32(xdrs, (int32_t *)&procnum)) ||
10747c478bd9Sstevel@tonic-gate (!AUTH_MARSHALL(h->cl_auth, xdrs, p->cku_cred)) ||
10757c478bd9Sstevel@tonic-gate (!(*xdr_args)(xdrs, argsp))) {
10767c478bd9Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTENCODEARGS;
10777c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EIO;
10787c478bd9Sstevel@tonic-gate goto cots_done;
10797c478bd9Sstevel@tonic-gate }
10807c478bd9Sstevel@tonic-gate
10817c478bd9Sstevel@tonic-gate (*(uint32_t *)(mp->b_rptr)) = p->cku_xid;
10827c478bd9Sstevel@tonic-gate } else {
10837c478bd9Sstevel@tonic-gate uint32_t *uproc = (uint32_t *)&p->cku_rpchdr[WIRE_HDR_SIZE];
10847c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(uproc, procnum);
10857c478bd9Sstevel@tonic-gate
10867c478bd9Sstevel@tonic-gate (*(uint32_t *)(&p->cku_rpchdr[0])) = p->cku_xid;
10877c478bd9Sstevel@tonic-gate
10887c478bd9Sstevel@tonic-gate /* Use XDR_SETPOS() to set the b_wptr. */
10897c478bd9Sstevel@tonic-gate XDR_SETPOS(xdrs, (uint_t)(mp->b_rptr - mp->b_datap->db_base));
10907c478bd9Sstevel@tonic-gate
10917c478bd9Sstevel@tonic-gate /* Serialize the procedure number and the arguments. */
10927c478bd9Sstevel@tonic-gate if (!AUTH_WRAP(h->cl_auth, p->cku_rpchdr, WIRE_HDR_SIZE+4,
10937c478bd9Sstevel@tonic-gate xdrs, xdr_args, argsp)) {
10947c478bd9Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTENCODEARGS;
10957c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EIO;
10967c478bd9Sstevel@tonic-gate goto cots_done;
10977c478bd9Sstevel@tonic-gate }
10987c478bd9Sstevel@tonic-gate }
10997c478bd9Sstevel@tonic-gate
11007c478bd9Sstevel@tonic-gate RPCLOG(2, "clnt_cots_kcallit: connected, sending call, tidu_size %d\n",
11017c478bd9Sstevel@tonic-gate tidu_size);
11027c478bd9Sstevel@tonic-gate
11037c478bd9Sstevel@tonic-gate wq = cm_entry->x_wq;
1104e280ed37SDai Ngo waitsecs = 0;
1105e280ed37SDai Ngo
1106e280ed37SDai Ngo dispatch_again:
1107125a8fd9SSiddheshwar Mahesh status = clnt_dispatch_send(wq, mp, call, p->cku_xid,
11087c478bd9Sstevel@tonic-gate (p->cku_flags & CKU_ONQUEUE));
11097c478bd9Sstevel@tonic-gate
1110e280ed37SDai Ngo if ((status == RPC_CANTSEND) && (call->call_reason == ENOBUFS)) {
1111125a8fd9SSiddheshwar Mahesh /*
1112e280ed37SDai Ngo * QFULL condition, allow some time for queue to drain
1113e280ed37SDai Ngo * and try again. Give up after waiting for all timeout
1114e280ed37SDai Ngo * specified for the call, or zone is going away.
1115125a8fd9SSiddheshwar Mahesh */
1116e280ed37SDai Ngo max_waitsecs = wait.tv_sec ? wait.tv_sec : clnt_cots_min_tout;
1117e280ed37SDai Ngo if ((waitsecs++ < max_waitsecs) &&
1118e280ed37SDai Ngo !(zone_status_get(curproc->p_zone) >=
1119e280ed37SDai Ngo ZONE_IS_SHUTTING_DOWN)) {
1120e280ed37SDai Ngo
1121e280ed37SDai Ngo /* wait 1 sec for queue to drain */
1122e280ed37SDai Ngo if (clnt_delay(drv_usectohz(1000000),
1123e280ed37SDai Ngo h->cl_nosignal) == EINTR) {
1124e280ed37SDai Ngo p->cku_err.re_errno = EINTR;
1125e280ed37SDai Ngo p->cku_err.re_status = RPC_INTR;
1126125a8fd9SSiddheshwar Mahesh
1127125a8fd9SSiddheshwar Mahesh goto cots_done;
1128125a8fd9SSiddheshwar Mahesh }
1129125a8fd9SSiddheshwar Mahesh
1130e280ed37SDai Ngo /* and try again */
1131e280ed37SDai Ngo goto dispatch_again;
1132e280ed37SDai Ngo }
1133e280ed37SDai Ngo p->cku_err.re_status = status;
1134e280ed37SDai Ngo p->cku_err.re_errno = call->call_reason;
1135e280ed37SDai Ngo DTRACE_PROBE(krpc__e__clntcots__kcallit__cantsend);
1136e280ed37SDai Ngo
1137e280ed37SDai Ngo goto cots_done;
1138e280ed37SDai Ngo }
1139e280ed37SDai Ngo
1140e280ed37SDai Ngo if (waitsecs) {
1141e280ed37SDai Ngo /* adjust timeout to account for time wait to send */
1142e280ed37SDai Ngo wait.tv_sec -= waitsecs;
1143e280ed37SDai Ngo if (wait.tv_sec < 0) {
1144e280ed37SDai Ngo /* pick up reply on next retry */
1145e280ed37SDai Ngo wait.tv_sec = 0;
1146e280ed37SDai Ngo }
1147e280ed37SDai Ngo DTRACE_PROBE2(clnt_cots__sendwait, CLIENT *, h,
1148e280ed37SDai Ngo int, waitsecs);
1149e280ed37SDai Ngo }
1150e280ed37SDai Ngo
11517c478bd9Sstevel@tonic-gate RPCLOG(64, "clnt_cots_kcallit: sent call for xid 0x%x\n",
11527c478bd9Sstevel@tonic-gate (uint_t)p->cku_xid);
11537c478bd9Sstevel@tonic-gate p->cku_flags = (CKU_ONQUEUE|CKU_SENT);
11547c478bd9Sstevel@tonic-gate p->cku_recv_attempts = 1;
11557c478bd9Sstevel@tonic-gate
11567c478bd9Sstevel@tonic-gate #ifdef RPCDEBUG
1157d3d50737SRafael Vanoni time_sent = ddi_get_lbolt();
11587c478bd9Sstevel@tonic-gate #endif
11597c478bd9Sstevel@tonic-gate
11607c478bd9Sstevel@tonic-gate /*
11617c478bd9Sstevel@tonic-gate * Wait for a reply or a timeout. If there is no error or timeout,
11627c478bd9Sstevel@tonic-gate * (both indicated by call_status), call->call_reply will contain
11637c478bd9Sstevel@tonic-gate * the RPC reply message.
11647c478bd9Sstevel@tonic-gate */
11657c478bd9Sstevel@tonic-gate read_again:
11667c478bd9Sstevel@tonic-gate mutex_enter(&call->call_lock);
11677c478bd9Sstevel@tonic-gate interrupted = 0;
11687c478bd9Sstevel@tonic-gate if (call->call_status == RPC_TIMEDOUT) {
11697c478bd9Sstevel@tonic-gate /*
11707c478bd9Sstevel@tonic-gate * Indicate that the lwp is not to be stopped while waiting
11717c478bd9Sstevel@tonic-gate * for this network traffic. This is to avoid deadlock while
11727c478bd9Sstevel@tonic-gate * debugging a process via /proc and also to avoid recursive
11737c478bd9Sstevel@tonic-gate * mutex_enter()s due to NFS page faults while stopping
11747c478bd9Sstevel@tonic-gate * (NFS holds locks when it calls here).
11757c478bd9Sstevel@tonic-gate */
11767c478bd9Sstevel@tonic-gate clock_t cv_wait_ret;
11777c478bd9Sstevel@tonic-gate clock_t timout;
11787c478bd9Sstevel@tonic-gate clock_t oldlbolt;
11797c478bd9Sstevel@tonic-gate
11807c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
11817c478bd9Sstevel@tonic-gate
11827c478bd9Sstevel@tonic-gate if (lwp != NULL)
11837c478bd9Sstevel@tonic-gate lwp->lwp_nostop++;
11847c478bd9Sstevel@tonic-gate
1185d3d50737SRafael Vanoni oldlbolt = ddi_get_lbolt();
11867c478bd9Sstevel@tonic-gate timout = wait.tv_sec * drv_usectohz(1000000) +
11877c478bd9Sstevel@tonic-gate drv_usectohz(wait.tv_usec) + oldlbolt;
11887c478bd9Sstevel@tonic-gate /*
11897c478bd9Sstevel@tonic-gate * Iterate until the call_status is changed to something
11907c478bd9Sstevel@tonic-gate * other that RPC_TIMEDOUT, or if cv_timedwait_sig() returns
11917c478bd9Sstevel@tonic-gate * something <=0 zero. The latter means that we timed
11927c478bd9Sstevel@tonic-gate * out.
11937c478bd9Sstevel@tonic-gate */
11947c478bd9Sstevel@tonic-gate if (h->cl_nosignal)
11957c478bd9Sstevel@tonic-gate while ((cv_wait_ret = cv_timedwait(&call->call_cv,
11967c478bd9Sstevel@tonic-gate &call->call_lock, timout)) > 0 &&
11978ffff9fdSgt29601 call->call_status == RPC_TIMEDOUT)
11988ffff9fdSgt29601 ;
11997c478bd9Sstevel@tonic-gate else
12007c478bd9Sstevel@tonic-gate while ((cv_wait_ret = cv_timedwait_sig(
12017c478bd9Sstevel@tonic-gate &call->call_cv,
12027c478bd9Sstevel@tonic-gate &call->call_lock, timout)) > 0 &&
12038ffff9fdSgt29601 call->call_status == RPC_TIMEDOUT)
12048ffff9fdSgt29601 ;
12057c478bd9Sstevel@tonic-gate
12067c478bd9Sstevel@tonic-gate switch (cv_wait_ret) {
12077c478bd9Sstevel@tonic-gate case 0:
12087c478bd9Sstevel@tonic-gate /*
12097c478bd9Sstevel@tonic-gate * If we got out of the above loop with
12107c478bd9Sstevel@tonic-gate * cv_timedwait_sig() returning 0, then we were
12117c478bd9Sstevel@tonic-gate * interrupted regardless what call_status is.
12127c478bd9Sstevel@tonic-gate */
12137c478bd9Sstevel@tonic-gate interrupted = 1;
12147c478bd9Sstevel@tonic-gate break;
12157c478bd9Sstevel@tonic-gate case -1:
12167c478bd9Sstevel@tonic-gate /* cv_timedwait_sig() timed out */
12177c478bd9Sstevel@tonic-gate break;
12187c478bd9Sstevel@tonic-gate default:
12197c478bd9Sstevel@tonic-gate
12207c478bd9Sstevel@tonic-gate /*
12217c478bd9Sstevel@tonic-gate * We were cv_signaled(). If we didn't
12227c478bd9Sstevel@tonic-gate * get a successful call_status and returned
12237c478bd9Sstevel@tonic-gate * before time expired, delay up to clnt_cots_min_tout
12247c478bd9Sstevel@tonic-gate * seconds so that the caller doesn't immediately
12257c478bd9Sstevel@tonic-gate * try to call us again and thus force the
12267c478bd9Sstevel@tonic-gate * same condition that got us here (such
12277c478bd9Sstevel@tonic-gate * as a RPC_XPRTFAILED due to the server not
12287c478bd9Sstevel@tonic-gate * listening on the end-point.
12297c478bd9Sstevel@tonic-gate */
12307c478bd9Sstevel@tonic-gate if (call->call_status != RPC_SUCCESS) {
12317c478bd9Sstevel@tonic-gate clock_t curlbolt;
12327c478bd9Sstevel@tonic-gate clock_t diff;
12337c478bd9Sstevel@tonic-gate
12347c478bd9Sstevel@tonic-gate curlbolt = ddi_get_lbolt();
12357c478bd9Sstevel@tonic-gate ticks = clnt_cots_min_tout *
12367c478bd9Sstevel@tonic-gate drv_usectohz(1000000);
12377c478bd9Sstevel@tonic-gate diff = curlbolt - oldlbolt;
12387c478bd9Sstevel@tonic-gate if (diff < ticks) {
12397c478bd9Sstevel@tonic-gate delay_first = TRUE;
12407c478bd9Sstevel@tonic-gate if (diff > 0)
12417c478bd9Sstevel@tonic-gate ticks -= diff;
12427c478bd9Sstevel@tonic-gate }
12437c478bd9Sstevel@tonic-gate }
12447c478bd9Sstevel@tonic-gate break;
12457c478bd9Sstevel@tonic-gate }
12467c478bd9Sstevel@tonic-gate
12477c478bd9Sstevel@tonic-gate if (lwp != NULL)
12487c478bd9Sstevel@tonic-gate lwp->lwp_nostop--;
12497c478bd9Sstevel@tonic-gate }
12507c478bd9Sstevel@tonic-gate /*
12517c478bd9Sstevel@tonic-gate * Get the reply message, if any. This will be freed at the end
12527c478bd9Sstevel@tonic-gate * whether or not an error occurred.
12537c478bd9Sstevel@tonic-gate */
12547c478bd9Sstevel@tonic-gate mp = call->call_reply;
12557c478bd9Sstevel@tonic-gate call->call_reply = NULL;
12567c478bd9Sstevel@tonic-gate
12577c478bd9Sstevel@tonic-gate /*
12587c478bd9Sstevel@tonic-gate * call_err is the error info when the call is on dispatch queue.
12597c478bd9Sstevel@tonic-gate * cku_err is the error info returned to the caller.
12607c478bd9Sstevel@tonic-gate * Sync cku_err with call_err for local message processing.
12617c478bd9Sstevel@tonic-gate */
12627c478bd9Sstevel@tonic-gate
12637c478bd9Sstevel@tonic-gate status = call->call_status;
12647c478bd9Sstevel@tonic-gate p->cku_err = call->call_err;
12657c478bd9Sstevel@tonic-gate mutex_exit(&call->call_lock);
12667c478bd9Sstevel@tonic-gate
12677c478bd9Sstevel@tonic-gate if (status != RPC_SUCCESS) {
12687c478bd9Sstevel@tonic-gate switch (status) {
12697c478bd9Sstevel@tonic-gate case RPC_TIMEDOUT:
1270d3d50737SRafael Vanoni now = ddi_get_lbolt();
12717c478bd9Sstevel@tonic-gate if (interrupted) {
12727c478bd9Sstevel@tonic-gate COTSRCSTAT_INCR(p->cku_stats, rcintrs);
12737c478bd9Sstevel@tonic-gate p->cku_err.re_status = RPC_INTR;
12747c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EINTR;
12757c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_cots_kcallit: xid 0x%x",
12767c478bd9Sstevel@tonic-gate p->cku_xid);
1277d3d50737SRafael Vanoni RPCLOG(1, "signal interrupted at %ld", now);
12787c478bd9Sstevel@tonic-gate RPCLOG(1, ", was sent at %ld\n", time_sent);
12797c478bd9Sstevel@tonic-gate } else {
12807c478bd9Sstevel@tonic-gate COTSRCSTAT_INCR(p->cku_stats, rctimeouts);
12817c478bd9Sstevel@tonic-gate p->cku_err.re_errno = ETIMEDOUT;
12827c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_cots_kcallit: timed out at %ld",
1283d3d50737SRafael Vanoni now);
12847c478bd9Sstevel@tonic-gate RPCLOG(1, ", was sent at %ld\n", time_sent);
12857c478bd9Sstevel@tonic-gate }
12867c478bd9Sstevel@tonic-gate break;
12877c478bd9Sstevel@tonic-gate
12887c478bd9Sstevel@tonic-gate case RPC_XPRTFAILED:
12897c478bd9Sstevel@tonic-gate if (p->cku_err.re_errno == 0)
12907c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EIO;
12917c478bd9Sstevel@tonic-gate
12927c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_cots_kcallit: transport failed: %d\n",
12937c478bd9Sstevel@tonic-gate p->cku_err.re_errno);
12947c478bd9Sstevel@tonic-gate break;
12957c478bd9Sstevel@tonic-gate
12967c478bd9Sstevel@tonic-gate case RPC_SYSTEMERROR:
12977c478bd9Sstevel@tonic-gate ASSERT(p->cku_err.re_errno);
12987c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_cots_kcallit: system error: %d\n",
12997c478bd9Sstevel@tonic-gate p->cku_err.re_errno);
13007c478bd9Sstevel@tonic-gate break;
13017c478bd9Sstevel@tonic-gate
13027c478bd9Sstevel@tonic-gate default:
13037c478bd9Sstevel@tonic-gate p->cku_err.re_status = RPC_SYSTEMERROR;
13047c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EIO;
13057c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_cots_kcallit: error: %s\n",
13067c478bd9Sstevel@tonic-gate clnt_sperrno(status));
13077c478bd9Sstevel@tonic-gate break;
13087c478bd9Sstevel@tonic-gate }
13097c478bd9Sstevel@tonic-gate if (p->cku_err.re_status != RPC_TIMEDOUT) {
13107c478bd9Sstevel@tonic-gate
13117c478bd9Sstevel@tonic-gate if (p->cku_flags & CKU_ONQUEUE) {
13127c478bd9Sstevel@tonic-gate call_table_remove(call);
13137c478bd9Sstevel@tonic-gate p->cku_flags &= ~CKU_ONQUEUE;
13147c478bd9Sstevel@tonic-gate }
13157c478bd9Sstevel@tonic-gate
13167c478bd9Sstevel@tonic-gate RPCLOG(64, "clnt_cots_kcallit: non TIMEOUT so xid 0x%x "
13177c478bd9Sstevel@tonic-gate "taken off dispatch list\n", p->cku_xid);
13187c478bd9Sstevel@tonic-gate if (call->call_reply) {
13197c478bd9Sstevel@tonic-gate freemsg(call->call_reply);
13207c478bd9Sstevel@tonic-gate call->call_reply = NULL;
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate } else if (wait.tv_sec != 0) {
13237c478bd9Sstevel@tonic-gate /*
13247c478bd9Sstevel@tonic-gate * We've sent the request over TCP and so we have
13257c478bd9Sstevel@tonic-gate * every reason to believe it will get
13267c478bd9Sstevel@tonic-gate * delivered. In which case returning a timeout is not
13277c478bd9Sstevel@tonic-gate * appropriate.
13287c478bd9Sstevel@tonic-gate */
13297c478bd9Sstevel@tonic-gate if (p->cku_progress == TRUE &&
13307c478bd9Sstevel@tonic-gate p->cku_recv_attempts < clnt_cots_maxrecv) {
13317c478bd9Sstevel@tonic-gate p->cku_err.re_status = RPC_INPROGRESS;
13327c478bd9Sstevel@tonic-gate }
13337c478bd9Sstevel@tonic-gate }
13347c478bd9Sstevel@tonic-gate goto cots_done;
13357c478bd9Sstevel@tonic-gate }
13367c478bd9Sstevel@tonic-gate
13377c478bd9Sstevel@tonic-gate xdrs = &p->cku_inxdr;
13387c478bd9Sstevel@tonic-gate xdrmblk_init(xdrs, mp, XDR_DECODE, 0);
13397c478bd9Sstevel@tonic-gate
13407c478bd9Sstevel@tonic-gate reply_msg.rm_direction = REPLY;
13417c478bd9Sstevel@tonic-gate reply_msg.rm_reply.rp_stat = MSG_ACCEPTED;
13427c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_stat = SUCCESS;
13437c478bd9Sstevel@tonic-gate
13447c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_verf = _null_auth;
13457c478bd9Sstevel@tonic-gate /*
13467c478bd9Sstevel@tonic-gate * xdr_results will be done in AUTH_UNWRAP.
13477c478bd9Sstevel@tonic-gate */
13487c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.where = NULL;
13497c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.proc = xdr_void;
13507c478bd9Sstevel@tonic-gate
13517c478bd9Sstevel@tonic-gate if (xdr_replymsg(xdrs, &reply_msg)) {
13527c478bd9Sstevel@tonic-gate enum clnt_stat re_status;
13537c478bd9Sstevel@tonic-gate
13547c478bd9Sstevel@tonic-gate _seterr_reply(&reply_msg, &p->cku_err);
13557c478bd9Sstevel@tonic-gate
13567c478bd9Sstevel@tonic-gate re_status = p->cku_err.re_status;
13577c478bd9Sstevel@tonic-gate if (re_status == RPC_SUCCESS) {
13587c478bd9Sstevel@tonic-gate /*
13597c478bd9Sstevel@tonic-gate * Reply is good, check auth.
13607c478bd9Sstevel@tonic-gate */
13617c478bd9Sstevel@tonic-gate if (!AUTH_VALIDATE(h->cl_auth,
13627c478bd9Sstevel@tonic-gate &reply_msg.acpted_rply.ar_verf)) {
13637c478bd9Sstevel@tonic-gate COTSRCSTAT_INCR(p->cku_stats, rcbadverfs);
13647c478bd9Sstevel@tonic-gate RPCLOG0(1, "clnt_cots_kcallit: validation "
13657c478bd9Sstevel@tonic-gate "failure\n");
13667c478bd9Sstevel@tonic-gate freemsg(mp);
13677c478bd9Sstevel@tonic-gate (void) xdr_rpc_free_verifier(xdrs, &reply_msg);
13687c478bd9Sstevel@tonic-gate mutex_enter(&call->call_lock);
13697c478bd9Sstevel@tonic-gate if (call->call_reply == NULL)
13707c478bd9Sstevel@tonic-gate call->call_status = RPC_TIMEDOUT;
13717c478bd9Sstevel@tonic-gate mutex_exit(&call->call_lock);
13727c478bd9Sstevel@tonic-gate goto read_again;
13737c478bd9Sstevel@tonic-gate } else if (!AUTH_UNWRAP(h->cl_auth, xdrs,
13747c478bd9Sstevel@tonic-gate xdr_results, resultsp)) {
13757c478bd9Sstevel@tonic-gate RPCLOG0(1, "clnt_cots_kcallit: validation "
13767c478bd9Sstevel@tonic-gate "failure (unwrap)\n");
13777c478bd9Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTDECODERES;
13787c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EIO;
13797c478bd9Sstevel@tonic-gate }
13807c478bd9Sstevel@tonic-gate } else {
13817c478bd9Sstevel@tonic-gate /* set errno in case we can't recover */
13827c478bd9Sstevel@tonic-gate if (re_status != RPC_VERSMISMATCH &&
13837c478bd9Sstevel@tonic-gate re_status != RPC_AUTHERROR &&
13847c478bd9Sstevel@tonic-gate re_status != RPC_PROGVERSMISMATCH)
13857c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EIO;
13867c478bd9Sstevel@tonic-gate
13877c478bd9Sstevel@tonic-gate if (re_status == RPC_AUTHERROR) {
13887c478bd9Sstevel@tonic-gate /*
1389a33e37fdSrg137905 * Maybe our credential need to be refreshed
13907c478bd9Sstevel@tonic-gate */
1391a85a6121Srg137905 if (cm_entry) {
1392a85a6121Srg137905 /*
1393a85a6121Srg137905 * There is the potential that the
1394a85a6121Srg137905 * cm_entry has/will be marked dead,
1395a33e37fdSrg137905 * so drop the connection altogether,
1396a33e37fdSrg137905 * force REFRESH to establish new
1397a33e37fdSrg137905 * connection.
1398a85a6121Srg137905 */
1399a33e37fdSrg137905 connmgr_cancelconn(cm_entry);
1400a85a6121Srg137905 cm_entry = NULL;
1401a85a6121Srg137905 }
1402a85a6121Srg137905
1403a85a6121Srg137905 (void) xdr_rpc_free_verifier(xdrs,
1404a85a6121Srg137905 &reply_msg);
14057c478bd9Sstevel@tonic-gate
14067c478bd9Sstevel@tonic-gate if (p->cku_flags & CKU_ONQUEUE) {
14077c478bd9Sstevel@tonic-gate call_table_remove(call);
14087c478bd9Sstevel@tonic-gate p->cku_flags &= ~CKU_ONQUEUE;
14097c478bd9Sstevel@tonic-gate }
1410a85a6121Srg137905 RPCLOG(64,
1411a85a6121Srg137905 "clnt_cots_kcallit: AUTH_ERROR, xid"
1412a85a6121Srg137905 " 0x%x removed off dispatch list\n",
14137c478bd9Sstevel@tonic-gate p->cku_xid);
14147c478bd9Sstevel@tonic-gate if (call->call_reply) {
14157c478bd9Sstevel@tonic-gate freemsg(call->call_reply);
14167c478bd9Sstevel@tonic-gate call->call_reply = NULL;
14177c478bd9Sstevel@tonic-gate }
1418a85a6121Srg137905
141928a15eaaSMarcel Telka if ((refreshes > 0) &&
142028a15eaaSMarcel Telka AUTH_REFRESH(h->cl_auth, &reply_msg,
142128a15eaaSMarcel Telka p->cku_cred)) {
142228a15eaaSMarcel Telka refreshes--;
142328a15eaaSMarcel Telka freemsg(mp);
142428a15eaaSMarcel Telka mp = NULL;
142528a15eaaSMarcel Telka
1426a85a6121Srg137905 COTSRCSTAT_INCR(p->cku_stats,
1427a85a6121Srg137905 rcbadcalls);
1428a85a6121Srg137905 COTSRCSTAT_INCR(p->cku_stats,
1429a85a6121Srg137905 rcnewcreds);
14307c478bd9Sstevel@tonic-gate goto call_again;
1431a33e37fdSrg137905 }
1432a33e37fdSrg137905
14337c478bd9Sstevel@tonic-gate /*
14347c478bd9Sstevel@tonic-gate * We have used the client handle to
14357c478bd9Sstevel@tonic-gate * do an AUTH_REFRESH and the RPC status may
14367c478bd9Sstevel@tonic-gate * be set to RPC_SUCCESS; Let's make sure to
14377c478bd9Sstevel@tonic-gate * set it to RPC_AUTHERROR.
14387c478bd9Sstevel@tonic-gate */
14397c478bd9Sstevel@tonic-gate p->cku_err.re_status = RPC_AUTHERROR;
1440a33e37fdSrg137905
14417c478bd9Sstevel@tonic-gate /*
14427c478bd9Sstevel@tonic-gate * Map recoverable and unrecoverable
14437c478bd9Sstevel@tonic-gate * authentication errors to appropriate errno
14447c478bd9Sstevel@tonic-gate */
14457c478bd9Sstevel@tonic-gate switch (p->cku_err.re_why) {
144678598ee3Snd150628 case AUTH_TOOWEAK:
144778598ee3Snd150628 /*
1448a85a6121Srg137905 * This could be a failure where the
1449a85a6121Srg137905 * server requires use of a reserved
1450a85a6121Srg137905 * port, check and optionally set the
1451a85a6121Srg137905 * client handle useresvport trying
1452a85a6121Srg137905 * one more time. Next go round we
1453a85a6121Srg137905 * fall out with the tooweak error.
145478598ee3Snd150628 */
145578598ee3Snd150628 if (p->cku_useresvport != 1) {
145678598ee3Snd150628 p->cku_useresvport = 1;
145778598ee3Snd150628 p->cku_xid = 0;
145878598ee3Snd150628 freemsg(mp);
145928a15eaaSMarcel Telka mp = NULL;
146078598ee3Snd150628 goto call_again;
146178598ee3Snd150628 }
146278598ee3Snd150628 /* FALLTHRU */
14637c478bd9Sstevel@tonic-gate case AUTH_BADCRED:
14647c478bd9Sstevel@tonic-gate case AUTH_BADVERF:
14657c478bd9Sstevel@tonic-gate case AUTH_INVALIDRESP:
14667c478bd9Sstevel@tonic-gate case AUTH_FAILED:
14677c478bd9Sstevel@tonic-gate case RPCSEC_GSS_NOCRED:
14687c478bd9Sstevel@tonic-gate case RPCSEC_GSS_FAILED:
14697c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EACCES;
14707c478bd9Sstevel@tonic-gate break;
14717c478bd9Sstevel@tonic-gate case AUTH_REJECTEDCRED:
14727c478bd9Sstevel@tonic-gate case AUTH_REJECTEDVERF:
14737c478bd9Sstevel@tonic-gate default: p->cku_err.re_errno = EIO;
14747c478bd9Sstevel@tonic-gate break;
14757c478bd9Sstevel@tonic-gate }
14767c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_cots_kcallit : authentication"
14777c478bd9Sstevel@tonic-gate " failed with RPC_AUTHERROR of type %d\n",
14787c478bd9Sstevel@tonic-gate (int)p->cku_err.re_why);
147928a15eaaSMarcel Telka goto cots_done;
14807c478bd9Sstevel@tonic-gate }
14817c478bd9Sstevel@tonic-gate }
14827c478bd9Sstevel@tonic-gate } else {
14837c478bd9Sstevel@tonic-gate /* reply didn't decode properly. */
14847c478bd9Sstevel@tonic-gate p->cku_err.re_status = RPC_CANTDECODERES;
14857c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EIO;
14867c478bd9Sstevel@tonic-gate RPCLOG0(1, "clnt_cots_kcallit: decode failure\n");
14877c478bd9Sstevel@tonic-gate }
14887c478bd9Sstevel@tonic-gate
14897c478bd9Sstevel@tonic-gate (void) xdr_rpc_free_verifier(xdrs, &reply_msg);
14907c478bd9Sstevel@tonic-gate
14917c478bd9Sstevel@tonic-gate if (p->cku_flags & CKU_ONQUEUE) {
14927c478bd9Sstevel@tonic-gate call_table_remove(call);
14937c478bd9Sstevel@tonic-gate p->cku_flags &= ~CKU_ONQUEUE;
14947c478bd9Sstevel@tonic-gate }
14957c478bd9Sstevel@tonic-gate
14967c478bd9Sstevel@tonic-gate RPCLOG(64, "clnt_cots_kcallit: xid 0x%x taken off dispatch list",
14977c478bd9Sstevel@tonic-gate p->cku_xid);
14987c478bd9Sstevel@tonic-gate RPCLOG(64, " status is %s\n", clnt_sperrno(p->cku_err.re_status));
14997c478bd9Sstevel@tonic-gate cots_done:
15007c478bd9Sstevel@tonic-gate if (cm_entry)
15017c478bd9Sstevel@tonic-gate connmgr_release(cm_entry);
15027c478bd9Sstevel@tonic-gate
15037c478bd9Sstevel@tonic-gate if (mp != NULL)
15047c478bd9Sstevel@tonic-gate freemsg(mp);
15057c478bd9Sstevel@tonic-gate if ((p->cku_flags & CKU_ONQUEUE) == 0 && call->call_reply) {
15067c478bd9Sstevel@tonic-gate freemsg(call->call_reply);
15077c478bd9Sstevel@tonic-gate call->call_reply = NULL;
15087c478bd9Sstevel@tonic-gate }
15097c478bd9Sstevel@tonic-gate if (p->cku_err.re_status != RPC_SUCCESS) {
15107c478bd9Sstevel@tonic-gate RPCLOG0(1, "clnt_cots_kcallit: tail-end failure\n");
15117c478bd9Sstevel@tonic-gate COTSRCSTAT_INCR(p->cku_stats, rcbadcalls);
15127c478bd9Sstevel@tonic-gate }
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate /*
15157c478bd9Sstevel@tonic-gate * No point in delaying if the zone is going away.
15167c478bd9Sstevel@tonic-gate */
15177c478bd9Sstevel@tonic-gate if (delay_first == TRUE &&
15187c478bd9Sstevel@tonic-gate !(zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN)) {
15197c478bd9Sstevel@tonic-gate if (clnt_delay(ticks, h->cl_nosignal) == EINTR) {
15207c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EINTR;
15217c478bd9Sstevel@tonic-gate p->cku_err.re_status = RPC_INTR;
15227c478bd9Sstevel@tonic-gate }
15237c478bd9Sstevel@tonic-gate }
15247c478bd9Sstevel@tonic-gate return (p->cku_err.re_status);
15257c478bd9Sstevel@tonic-gate }
15267c478bd9Sstevel@tonic-gate
15277c478bd9Sstevel@tonic-gate /*
15287c478bd9Sstevel@tonic-gate * Kinit routine for cots. This sets up the correct operations in
15297c478bd9Sstevel@tonic-gate * the client handle, as the handle may have previously been a clts
15307c478bd9Sstevel@tonic-gate * handle, and clears the xid field so there is no way a new call
15317c478bd9Sstevel@tonic-gate * could be mistaken for a retry. It also sets in the handle the
15327c478bd9Sstevel@tonic-gate * information that is passed at create/kinit time but needed at
15337c478bd9Sstevel@tonic-gate * call time, as cots creates the transport at call time - device,
15347c478bd9Sstevel@tonic-gate * address of the server, protocol family.
15357c478bd9Sstevel@tonic-gate */
15367c478bd9Sstevel@tonic-gate void
clnt_cots_kinit(CLIENT * h,dev_t dev,int family,struct netbuf * addr,int max_msgsize,cred_t * cred)15377c478bd9Sstevel@tonic-gate clnt_cots_kinit(CLIENT *h, dev_t dev, int family, struct netbuf *addr,
15387c478bd9Sstevel@tonic-gate int max_msgsize, cred_t *cred)
15397c478bd9Sstevel@tonic-gate {
15407c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
15417c478bd9Sstevel@tonic-gate cku_private_t *p = htop(h);
15427c478bd9Sstevel@tonic-gate calllist_t *call = &p->cku_call;
15437c478bd9Sstevel@tonic-gate
15447c478bd9Sstevel@tonic-gate h->cl_ops = &tcp_ops;
15457c478bd9Sstevel@tonic-gate if (p->cku_flags & CKU_ONQUEUE) {
15467c478bd9Sstevel@tonic-gate call_table_remove(call);
15477c478bd9Sstevel@tonic-gate p->cku_flags &= ~CKU_ONQUEUE;
15487c478bd9Sstevel@tonic-gate RPCLOG(64, "clnt_cots_kinit: removing call for xid 0x%x from"
15497c478bd9Sstevel@tonic-gate " dispatch list\n", p->cku_xid);
15507c478bd9Sstevel@tonic-gate }
15517c478bd9Sstevel@tonic-gate
15527c478bd9Sstevel@tonic-gate if (call->call_reply != NULL) {
15537c478bd9Sstevel@tonic-gate freemsg(call->call_reply);
15547c478bd9Sstevel@tonic-gate call->call_reply = NULL;
15557c478bd9Sstevel@tonic-gate }
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate call->call_bucket = NULL;
15587c478bd9Sstevel@tonic-gate call->call_hash = 0;
15597c478bd9Sstevel@tonic-gate
15607c478bd9Sstevel@tonic-gate /*
15617c478bd9Sstevel@tonic-gate * We don't clear cku_flags here, because clnt_cots_kcallit()
15627c478bd9Sstevel@tonic-gate * takes care of handling the cku_flags reset.
15637c478bd9Sstevel@tonic-gate */
15647c478bd9Sstevel@tonic-gate p->cku_xid = 0;
15657c478bd9Sstevel@tonic-gate p->cku_device = dev;
15667c478bd9Sstevel@tonic-gate p->cku_addrfmly = family;
15677c478bd9Sstevel@tonic-gate p->cku_cred = cred;
15687c478bd9Sstevel@tonic-gate
15697c478bd9Sstevel@tonic-gate if (p->cku_addr.maxlen < addr->len) {
15707c478bd9Sstevel@tonic-gate if (p->cku_addr.maxlen != 0 && p->cku_addr.buf != NULL)
15717c478bd9Sstevel@tonic-gate kmem_free(p->cku_addr.buf, p->cku_addr.maxlen);
15727c478bd9Sstevel@tonic-gate p->cku_addr.buf = kmem_zalloc(addr->maxlen, KM_SLEEP);
15737c478bd9Sstevel@tonic-gate p->cku_addr.maxlen = addr->maxlen;
15747c478bd9Sstevel@tonic-gate }
15757c478bd9Sstevel@tonic-gate
15767c478bd9Sstevel@tonic-gate p->cku_addr.len = addr->len;
15777c478bd9Sstevel@tonic-gate bcopy(addr->buf, p->cku_addr.buf, addr->len);
15787c478bd9Sstevel@tonic-gate
15797c478bd9Sstevel@tonic-gate /*
15807c478bd9Sstevel@tonic-gate * If the current sanity check size in rpcmod is smaller
15817c478bd9Sstevel@tonic-gate * than the size needed, then increase the sanity check.
15827c478bd9Sstevel@tonic-gate */
15837c478bd9Sstevel@tonic-gate if (max_msgsize != 0 && clnt_max_msg_sizep != NULL &&
15847c478bd9Sstevel@tonic-gate max_msgsize > *clnt_max_msg_sizep) {
15857c478bd9Sstevel@tonic-gate mutex_enter(&clnt_max_msg_lock);
15867c478bd9Sstevel@tonic-gate if (max_msgsize > *clnt_max_msg_sizep)
15877c478bd9Sstevel@tonic-gate *clnt_max_msg_sizep = max_msgsize;
15887c478bd9Sstevel@tonic-gate mutex_exit(&clnt_max_msg_lock);
15897c478bd9Sstevel@tonic-gate }
15907c478bd9Sstevel@tonic-gate }
15917c478bd9Sstevel@tonic-gate
15927c478bd9Sstevel@tonic-gate /*
15937c478bd9Sstevel@tonic-gate * ksettimers is a no-op for cots, with the exception of setting the xid.
15947c478bd9Sstevel@tonic-gate */
15957c478bd9Sstevel@tonic-gate /* ARGSUSED */
15967c478bd9Sstevel@tonic-gate static int
clnt_cots_ksettimers(CLIENT * h,struct rpc_timers * t,struct rpc_timers * all,int minimum,void (* feedback)(int,int,caddr_t),caddr_t arg,uint32_t xid)15977c478bd9Sstevel@tonic-gate clnt_cots_ksettimers(CLIENT *h, struct rpc_timers *t, struct rpc_timers *all,
15987c478bd9Sstevel@tonic-gate int minimum, void (*feedback)(int, int, caddr_t), caddr_t arg,
15997c478bd9Sstevel@tonic-gate uint32_t xid)
16007c478bd9Sstevel@tonic-gate {
16017c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */
16027c478bd9Sstevel@tonic-gate cku_private_t *p = htop(h);
16037c478bd9Sstevel@tonic-gate
16047c478bd9Sstevel@tonic-gate if (xid)
16057c478bd9Sstevel@tonic-gate p->cku_xid = xid;
16067c478bd9Sstevel@tonic-gate COTSRCSTAT_INCR(p->cku_stats, rctimers);
16077c478bd9Sstevel@tonic-gate return (0);
16087c478bd9Sstevel@tonic-gate }
16097c478bd9Sstevel@tonic-gate
16107c478bd9Sstevel@tonic-gate extern void rpc_poptimod(struct vnode *);
16117c478bd9Sstevel@tonic-gate extern int kstr_push(struct vnode *, char *);
16127c478bd9Sstevel@tonic-gate
16137c478bd9Sstevel@tonic-gate int
conn_kstat_update(kstat_t * ksp,int rw)16147c478bd9Sstevel@tonic-gate conn_kstat_update(kstat_t *ksp, int rw)
16157c478bd9Sstevel@tonic-gate {
16167c478bd9Sstevel@tonic-gate struct cm_xprt *cm_entry;
16177c478bd9Sstevel@tonic-gate struct cm_kstat_xprt *cm_ksp_data;
16187c478bd9Sstevel@tonic-gate uchar_t *b;
16197c478bd9Sstevel@tonic-gate char *fbuf;
16207c478bd9Sstevel@tonic-gate
16217c478bd9Sstevel@tonic-gate if (rw == KSTAT_WRITE)
16227c478bd9Sstevel@tonic-gate return (EACCES);
16237c478bd9Sstevel@tonic-gate if (ksp == NULL || ksp->ks_private == NULL)
16247c478bd9Sstevel@tonic-gate return (EIO);
16257c478bd9Sstevel@tonic-gate cm_entry = (struct cm_xprt *)ksp->ks_private;
16267c478bd9Sstevel@tonic-gate cm_ksp_data = (struct cm_kstat_xprt *)ksp->ks_data;
16277c478bd9Sstevel@tonic-gate
16287c478bd9Sstevel@tonic-gate cm_ksp_data->x_wq.value.ui32 = (uint32_t)(uintptr_t)cm_entry->x_wq;
16297c478bd9Sstevel@tonic-gate cm_ksp_data->x_family.value.ui32 = cm_entry->x_family;
16307c478bd9Sstevel@tonic-gate cm_ksp_data->x_rdev.value.ui32 = (uint32_t)cm_entry->x_rdev;
16317c478bd9Sstevel@tonic-gate cm_ksp_data->x_time.value.ui32 = cm_entry->x_time;
16327c478bd9Sstevel@tonic-gate cm_ksp_data->x_ref.value.ui32 = cm_entry->x_ref;
16337c478bd9Sstevel@tonic-gate cm_ksp_data->x_state.value.ui32 = cm_entry->x_state_flags;
16347c478bd9Sstevel@tonic-gate
16357c478bd9Sstevel@tonic-gate if (cm_entry->x_server.buf) {
1636a1b5e537Sbmc fbuf = cm_ksp_data->x_server.value.str.addr.ptr;
16377c478bd9Sstevel@tonic-gate if (cm_entry->x_family == AF_INET &&
16387c478bd9Sstevel@tonic-gate cm_entry->x_server.len ==
16397c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in)) {
16407c478bd9Sstevel@tonic-gate struct sockaddr_in *sa;
16417c478bd9Sstevel@tonic-gate sa = (struct sockaddr_in *)
16427c478bd9Sstevel@tonic-gate cm_entry->x_server.buf;
16437c478bd9Sstevel@tonic-gate b = (uchar_t *)&sa->sin_addr;
16447c478bd9Sstevel@tonic-gate (void) sprintf(fbuf,
16457c478bd9Sstevel@tonic-gate "%03d.%03d.%03d.%03d", b[0] & 0xFF, b[1] & 0xFF,
16467c478bd9Sstevel@tonic-gate b[2] & 0xFF, b[3] & 0xFF);
16477c478bd9Sstevel@tonic-gate cm_ksp_data->x_port.value.ui32 =
16487c478bd9Sstevel@tonic-gate (uint32_t)sa->sin_port;
16497c478bd9Sstevel@tonic-gate } else if (cm_entry->x_family == AF_INET6 &&
16507c478bd9Sstevel@tonic-gate cm_entry->x_server.len >=
16517c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in6)) {
16527c478bd9Sstevel@tonic-gate /* extract server IP address & port */
16537c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6;
16547c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)cm_entry->x_server.buf;
16557c478bd9Sstevel@tonic-gate (void) kinet_ntop6((uchar_t *)&sin6->sin6_addr, fbuf,
16567c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN);
16577c478bd9Sstevel@tonic-gate cm_ksp_data->x_port.value.ui32 = sin6->sin6_port;
16587c478bd9Sstevel@tonic-gate } else {
16597c478bd9Sstevel@tonic-gate struct sockaddr_in *sa;
16607c478bd9Sstevel@tonic-gate
16617c478bd9Sstevel@tonic-gate sa = (struct sockaddr_in *)cm_entry->x_server.buf;
16627c478bd9Sstevel@tonic-gate b = (uchar_t *)&sa->sin_addr;
16637c478bd9Sstevel@tonic-gate (void) sprintf(fbuf,
16647c478bd9Sstevel@tonic-gate "%03d.%03d.%03d.%03d", b[0] & 0xFF, b[1] & 0xFF,
16657c478bd9Sstevel@tonic-gate b[2] & 0xFF, b[3] & 0xFF);
16667c478bd9Sstevel@tonic-gate }
16677c478bd9Sstevel@tonic-gate KSTAT_NAMED_STR_BUFLEN(&cm_ksp_data->x_server) =
16687c478bd9Sstevel@tonic-gate strlen(fbuf) + 1;
16697c478bd9Sstevel@tonic-gate }
16707c478bd9Sstevel@tonic-gate
16717c478bd9Sstevel@tonic-gate return (0);
16727c478bd9Sstevel@tonic-gate }
16737c478bd9Sstevel@tonic-gate
16747c478bd9Sstevel@tonic-gate
16757c478bd9Sstevel@tonic-gate /*
16767c478bd9Sstevel@tonic-gate * We want a version of delay which is interruptible by a UNIX signal
16777c478bd9Sstevel@tonic-gate * Return EINTR if an interrupt occured.
16787c478bd9Sstevel@tonic-gate */
16797c478bd9Sstevel@tonic-gate static int
clnt_delay(clock_t ticks,bool_t nosignal)16807c478bd9Sstevel@tonic-gate clnt_delay(clock_t ticks, bool_t nosignal)
16817c478bd9Sstevel@tonic-gate {
16827c478bd9Sstevel@tonic-gate if (nosignal == TRUE) {
16837c478bd9Sstevel@tonic-gate delay(ticks);
16847c478bd9Sstevel@tonic-gate return (0);
16857c478bd9Sstevel@tonic-gate }
16867c478bd9Sstevel@tonic-gate return (delay_sig(ticks));
16877c478bd9Sstevel@tonic-gate }
16887c478bd9Sstevel@tonic-gate
16897c478bd9Sstevel@tonic-gate /*
16907c478bd9Sstevel@tonic-gate * Wait for a connection until a timeout, or until we are
16917c478bd9Sstevel@tonic-gate * signalled that there has been a connection state change.
16927c478bd9Sstevel@tonic-gate */
16937c478bd9Sstevel@tonic-gate static enum clnt_stat
connmgr_cwait(struct cm_xprt * cm_entry,const struct timeval * waitp,bool_t nosignal)16947c478bd9Sstevel@tonic-gate connmgr_cwait(struct cm_xprt *cm_entry, const struct timeval *waitp,
16957c478bd9Sstevel@tonic-gate bool_t nosignal)
16967c478bd9Sstevel@tonic-gate {
16977c478bd9Sstevel@tonic-gate bool_t interrupted;
16987c478bd9Sstevel@tonic-gate clock_t timout, cv_stat;
16997c478bd9Sstevel@tonic-gate enum clnt_stat clstat;
17007c478bd9Sstevel@tonic-gate unsigned int old_state;
17017c478bd9Sstevel@tonic-gate
17027c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&connmgr_lock));
17037c478bd9Sstevel@tonic-gate /*
17047c478bd9Sstevel@tonic-gate * We wait for the transport connection to be made, or an
17057c478bd9Sstevel@tonic-gate * indication that it could not be made.
17067c478bd9Sstevel@tonic-gate */
17077c478bd9Sstevel@tonic-gate clstat = RPC_TIMEDOUT;
17087c478bd9Sstevel@tonic-gate interrupted = FALSE;
17097c478bd9Sstevel@tonic-gate
17107c478bd9Sstevel@tonic-gate old_state = cm_entry->x_state_flags;
17117c478bd9Sstevel@tonic-gate /*
17127c478bd9Sstevel@tonic-gate * Now loop until cv_timedwait{_sig} returns because of
17137c478bd9Sstevel@tonic-gate * a signal(0) or timeout(-1) or cv_signal(>0). But it may be
17147c478bd9Sstevel@tonic-gate * cv_signalled for various other reasons too. So loop
17157c478bd9Sstevel@tonic-gate * until there is a state change on the connection.
17167c478bd9Sstevel@tonic-gate */
17177c478bd9Sstevel@tonic-gate
17187c478bd9Sstevel@tonic-gate timout = waitp->tv_sec * drv_usectohz(1000000) +
1719d3d50737SRafael Vanoni drv_usectohz(waitp->tv_usec) + ddi_get_lbolt();
17207c478bd9Sstevel@tonic-gate
17217c478bd9Sstevel@tonic-gate if (nosignal) {
17227c478bd9Sstevel@tonic-gate while ((cv_stat = cv_timedwait(&cm_entry->x_conn_cv,
17237c478bd9Sstevel@tonic-gate &connmgr_lock, timout)) > 0 &&
17247c478bd9Sstevel@tonic-gate cm_entry->x_state_flags == old_state)
17257c478bd9Sstevel@tonic-gate ;
17267c478bd9Sstevel@tonic-gate } else {
17277c478bd9Sstevel@tonic-gate while ((cv_stat = cv_timedwait_sig(&cm_entry->x_conn_cv,
17287c478bd9Sstevel@tonic-gate &connmgr_lock, timout)) > 0 &&
17297c478bd9Sstevel@tonic-gate cm_entry->x_state_flags == old_state)
17307c478bd9Sstevel@tonic-gate ;
17317c478bd9Sstevel@tonic-gate
17327c478bd9Sstevel@tonic-gate if (cv_stat == 0) /* got intr signal? */
17337c478bd9Sstevel@tonic-gate interrupted = TRUE;
17347c478bd9Sstevel@tonic-gate }
17357c478bd9Sstevel@tonic-gate
17367c478bd9Sstevel@tonic-gate if ((cm_entry->x_state_flags & (X_BADSTATES|X_CONNECTED)) ==
17377c478bd9Sstevel@tonic-gate X_CONNECTED) {
17387c478bd9Sstevel@tonic-gate clstat = RPC_SUCCESS;
17397c478bd9Sstevel@tonic-gate } else {
17407c478bd9Sstevel@tonic-gate if (interrupted == TRUE)
17417c478bd9Sstevel@tonic-gate clstat = RPC_INTR;
17427c478bd9Sstevel@tonic-gate RPCLOG(1, "connmgr_cwait: can't connect, error: %s\n",
17437c478bd9Sstevel@tonic-gate clnt_sperrno(clstat));
17447c478bd9Sstevel@tonic-gate }
17457c478bd9Sstevel@tonic-gate
17467c478bd9Sstevel@tonic-gate return (clstat);
17477c478bd9Sstevel@tonic-gate }
17487c478bd9Sstevel@tonic-gate
17497c478bd9Sstevel@tonic-gate /*
17507c478bd9Sstevel@tonic-gate * Primary interface for how RPC grabs a connection.
17517c478bd9Sstevel@tonic-gate */
17527c478bd9Sstevel@tonic-gate static struct cm_xprt *
connmgr_wrapget(struct netbuf * retryaddr,const struct timeval * waitp,cku_private_t * p)17537c478bd9Sstevel@tonic-gate connmgr_wrapget(
17547c478bd9Sstevel@tonic-gate struct netbuf *retryaddr,
17557c478bd9Sstevel@tonic-gate const struct timeval *waitp,
17567c478bd9Sstevel@tonic-gate cku_private_t *p)
17577c478bd9Sstevel@tonic-gate {
17587c478bd9Sstevel@tonic-gate struct cm_xprt *cm_entry;
17597c478bd9Sstevel@tonic-gate
17607c478bd9Sstevel@tonic-gate cm_entry = connmgr_get(retryaddr, waitp, &p->cku_addr, p->cku_addrfmly,
17617c478bd9Sstevel@tonic-gate &p->cku_srcaddr, &p->cku_err, p->cku_device,
1762de8c4a14SErik Nordmark p->cku_client.cl_nosignal, p->cku_useresvport, p->cku_cred);
17637c478bd9Sstevel@tonic-gate
17647c478bd9Sstevel@tonic-gate if (cm_entry == NULL) {
17657c478bd9Sstevel@tonic-gate /*
17667c478bd9Sstevel@tonic-gate * Re-map the call status to RPC_INTR if the err code is
17677c478bd9Sstevel@tonic-gate * EINTR. This can happen if calls status is RPC_TLIERROR.
17687c478bd9Sstevel@tonic-gate * However, don't re-map if signalling has been turned off.
17697c478bd9Sstevel@tonic-gate * XXX Really need to create a separate thread whenever
17707c478bd9Sstevel@tonic-gate * there isn't an existing connection.
17717c478bd9Sstevel@tonic-gate */
17727c478bd9Sstevel@tonic-gate if (p->cku_err.re_errno == EINTR) {
17737c478bd9Sstevel@tonic-gate if (p->cku_client.cl_nosignal == TRUE)
17747c478bd9Sstevel@tonic-gate p->cku_err.re_errno = EIO;
17757c478bd9Sstevel@tonic-gate else
17767c478bd9Sstevel@tonic-gate p->cku_err.re_status = RPC_INTR;
17777c478bd9Sstevel@tonic-gate }
17787c478bd9Sstevel@tonic-gate }
17797c478bd9Sstevel@tonic-gate
17807c478bd9Sstevel@tonic-gate return (cm_entry);
17817c478bd9Sstevel@tonic-gate }
17827c478bd9Sstevel@tonic-gate
17837c478bd9Sstevel@tonic-gate /*
17847c478bd9Sstevel@tonic-gate * Obtains a transport to the server specified in addr. If a suitable transport
17857c478bd9Sstevel@tonic-gate * does not already exist in the list of cached transports, a new connection
17867c478bd9Sstevel@tonic-gate * is created, connected, and added to the list. The connection is for sending
17877c478bd9Sstevel@tonic-gate * only - the reply message may come back on another transport connection.
178881dbf0b5SDai Ngo *
178981dbf0b5SDai Ngo * To implement round-robin load balancing with multiple client connections,
179081dbf0b5SDai Ngo * the last entry on the list is always selected. Once the entry is selected
179181dbf0b5SDai Ngo * it's re-inserted to the head of the list.
17927c478bd9Sstevel@tonic-gate */
17937c478bd9Sstevel@tonic-gate static struct cm_xprt *
connmgr_get(struct netbuf * retryaddr,const struct timeval * waitp,struct netbuf * destaddr,int addrfmly,struct netbuf * srcaddr,struct rpc_err * rpcerr,dev_t device,bool_t nosignal,int useresvport,cred_t * cr)17947c478bd9Sstevel@tonic-gate connmgr_get(
17957c478bd9Sstevel@tonic-gate struct netbuf *retryaddr,
17967c478bd9Sstevel@tonic-gate const struct timeval *waitp, /* changed to a ptr to converse stack */
17977c478bd9Sstevel@tonic-gate struct netbuf *destaddr,
17987c478bd9Sstevel@tonic-gate int addrfmly,
17997c478bd9Sstevel@tonic-gate struct netbuf *srcaddr,
18007c478bd9Sstevel@tonic-gate struct rpc_err *rpcerr,
18017c478bd9Sstevel@tonic-gate dev_t device,
18027c478bd9Sstevel@tonic-gate bool_t nosignal,
1803de8c4a14SErik Nordmark int useresvport,
1804de8c4a14SErik Nordmark cred_t *cr)
18057c478bd9Sstevel@tonic-gate {
18067c478bd9Sstevel@tonic-gate struct cm_xprt *cm_entry;
18077c478bd9Sstevel@tonic-gate struct cm_xprt *lru_entry;
180881dbf0b5SDai Ngo struct cm_xprt **cmp, **prev;
18097c478bd9Sstevel@tonic-gate queue_t *wq;
18107c478bd9Sstevel@tonic-gate TIUSER *tiptr;
18117c478bd9Sstevel@tonic-gate int i;
18127c478bd9Sstevel@tonic-gate int retval;
18137c478bd9Sstevel@tonic-gate int tidu_size;
18147c478bd9Sstevel@tonic-gate bool_t connected;
1815108322fbScarlsonj zoneid_t zoneid = rpc_zoneid();
18167c478bd9Sstevel@tonic-gate
18177c478bd9Sstevel@tonic-gate /*
18187c478bd9Sstevel@tonic-gate * If the call is not a retry, look for a transport entry that
18197c478bd9Sstevel@tonic-gate * goes to the server of interest.
18207c478bd9Sstevel@tonic-gate */
18217c478bd9Sstevel@tonic-gate mutex_enter(&connmgr_lock);
18227c478bd9Sstevel@tonic-gate
18237c478bd9Sstevel@tonic-gate if (retryaddr == NULL) {
18247c478bd9Sstevel@tonic-gate use_new_conn:
18257c478bd9Sstevel@tonic-gate i = 0;
18267c478bd9Sstevel@tonic-gate cm_entry = lru_entry = NULL;
18277c478bd9Sstevel@tonic-gate
182881dbf0b5SDai Ngo prev = cmp = &cm_hd;
18297c478bd9Sstevel@tonic-gate while ((cm_entry = *cmp) != NULL) {
18307c478bd9Sstevel@tonic-gate ASSERT(cm_entry != cm_entry->x_next);
18317c478bd9Sstevel@tonic-gate /*
18327c478bd9Sstevel@tonic-gate * Garbage collect conections that are marked
18337c478bd9Sstevel@tonic-gate * for needs disconnect.
18347c478bd9Sstevel@tonic-gate */
18357c478bd9Sstevel@tonic-gate if (cm_entry->x_needdis) {
1836418d27f3Sshepler CONN_HOLD(cm_entry);
18377c478bd9Sstevel@tonic-gate connmgr_dis_and_wait(cm_entry);
1838418d27f3Sshepler connmgr_release(cm_entry);
18397c478bd9Sstevel@tonic-gate /*
18407c478bd9Sstevel@tonic-gate * connmgr_lock could have been
18417c478bd9Sstevel@tonic-gate * dropped for the disconnect
18427c478bd9Sstevel@tonic-gate * processing so start over.
18437c478bd9Sstevel@tonic-gate */
18447c478bd9Sstevel@tonic-gate goto use_new_conn;
18457c478bd9Sstevel@tonic-gate }
18467c478bd9Sstevel@tonic-gate
18477c478bd9Sstevel@tonic-gate /*
18487c478bd9Sstevel@tonic-gate * Garbage collect the dead connections that have
18497c478bd9Sstevel@tonic-gate * no threads working on them.
18507c478bd9Sstevel@tonic-gate */
18517c478bd9Sstevel@tonic-gate if ((cm_entry->x_state_flags & (X_DEAD|X_THREAD)) ==
18527c478bd9Sstevel@tonic-gate X_DEAD) {
18538f7c43eaSmaheshvs mutex_enter(&cm_entry->x_lock);
18548f7c43eaSmaheshvs if (cm_entry->x_ref != 0) {
18558f7c43eaSmaheshvs /*
18568f7c43eaSmaheshvs * Currently in use.
18578f7c43eaSmaheshvs * Cleanup later.
18588f7c43eaSmaheshvs */
18598f7c43eaSmaheshvs cmp = &cm_entry->x_next;
18608f7c43eaSmaheshvs mutex_exit(&cm_entry->x_lock);
18618f7c43eaSmaheshvs continue;
18628f7c43eaSmaheshvs }
18638f7c43eaSmaheshvs mutex_exit(&cm_entry->x_lock);
18647c478bd9Sstevel@tonic-gate *cmp = cm_entry->x_next;
18657c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
18667c478bd9Sstevel@tonic-gate connmgr_close(cm_entry);
18677c478bd9Sstevel@tonic-gate mutex_enter(&connmgr_lock);
18687c478bd9Sstevel@tonic-gate goto use_new_conn;
18697c478bd9Sstevel@tonic-gate }
18707c478bd9Sstevel@tonic-gate
18717c478bd9Sstevel@tonic-gate
18727c478bd9Sstevel@tonic-gate if ((cm_entry->x_state_flags & X_BADSTATES) == 0 &&
18737c478bd9Sstevel@tonic-gate cm_entry->x_zoneid == zoneid &&
18747c478bd9Sstevel@tonic-gate cm_entry->x_rdev == device &&
18757c478bd9Sstevel@tonic-gate destaddr->len == cm_entry->x_server.len &&
18767c478bd9Sstevel@tonic-gate bcmp(destaddr->buf, cm_entry->x_server.buf,
18777c478bd9Sstevel@tonic-gate destaddr->len) == 0) {
18787c478bd9Sstevel@tonic-gate /*
18797c478bd9Sstevel@tonic-gate * If the matching entry isn't connected,
18807c478bd9Sstevel@tonic-gate * attempt to reconnect it.
18817c478bd9Sstevel@tonic-gate */
18827c478bd9Sstevel@tonic-gate if (cm_entry->x_connected == FALSE) {
18837c478bd9Sstevel@tonic-gate /*
18847c478bd9Sstevel@tonic-gate * We don't go through trying
18857c478bd9Sstevel@tonic-gate * to find the least recently
18867c478bd9Sstevel@tonic-gate * used connected because
18877c478bd9Sstevel@tonic-gate * connmgr_reconnect() briefly
18887c478bd9Sstevel@tonic-gate * dropped the connmgr_lock,
18897c478bd9Sstevel@tonic-gate * allowing a window for our
18907c478bd9Sstevel@tonic-gate * accounting to be messed up.
18917c478bd9Sstevel@tonic-gate * In any case, a re-connected
18927c478bd9Sstevel@tonic-gate * connection is as good as
18937c478bd9Sstevel@tonic-gate * a LRU connection.
18947c478bd9Sstevel@tonic-gate */
18957c478bd9Sstevel@tonic-gate return (connmgr_wrapconnect(cm_entry,
18967c478bd9Sstevel@tonic-gate waitp, destaddr, addrfmly, srcaddr,
1897de8c4a14SErik Nordmark rpcerr, TRUE, nosignal, cr));
18987c478bd9Sstevel@tonic-gate }
18997c478bd9Sstevel@tonic-gate i++;
190081dbf0b5SDai Ngo
190181dbf0b5SDai Ngo /* keep track of the last entry */
19027c478bd9Sstevel@tonic-gate lru_entry = cm_entry;
190381dbf0b5SDai Ngo prev = cmp;
19047c478bd9Sstevel@tonic-gate }
19057c478bd9Sstevel@tonic-gate cmp = &cm_entry->x_next;
19067c478bd9Sstevel@tonic-gate }
19077c478bd9Sstevel@tonic-gate
19087c478bd9Sstevel@tonic-gate if (i > clnt_max_conns) {
19097c478bd9Sstevel@tonic-gate RPCLOG(8, "connmgr_get: too many conns, dooming entry"
19107c478bd9Sstevel@tonic-gate " %p\n", (void *)lru_entry->x_tiptr);
19117c478bd9Sstevel@tonic-gate lru_entry->x_doomed = TRUE;
19127c478bd9Sstevel@tonic-gate goto use_new_conn;
19137c478bd9Sstevel@tonic-gate }
19147c478bd9Sstevel@tonic-gate
19157c478bd9Sstevel@tonic-gate /*
19167c478bd9Sstevel@tonic-gate * If we are at the maximum number of connections to
19177c478bd9Sstevel@tonic-gate * the server, hand back the least recently used one.
19187c478bd9Sstevel@tonic-gate */
19197c478bd9Sstevel@tonic-gate if (i == clnt_max_conns) {
19207c478bd9Sstevel@tonic-gate /*
19217c478bd9Sstevel@tonic-gate * Copy into the handle the source address of
19227c478bd9Sstevel@tonic-gate * the connection, which we will use in case of
19237c478bd9Sstevel@tonic-gate * a later retry.
19247c478bd9Sstevel@tonic-gate */
19257c478bd9Sstevel@tonic-gate if (srcaddr->len != lru_entry->x_src.len) {
19267c478bd9Sstevel@tonic-gate if (srcaddr->len > 0)
19277c478bd9Sstevel@tonic-gate kmem_free(srcaddr->buf,
19287c478bd9Sstevel@tonic-gate srcaddr->maxlen);
19297c478bd9Sstevel@tonic-gate srcaddr->buf = kmem_zalloc(
19307c478bd9Sstevel@tonic-gate lru_entry->x_src.len, KM_SLEEP);
19317c478bd9Sstevel@tonic-gate srcaddr->maxlen = srcaddr->len =
19327c478bd9Sstevel@tonic-gate lru_entry->x_src.len;
19337c478bd9Sstevel@tonic-gate }
19347c478bd9Sstevel@tonic-gate bcopy(lru_entry->x_src.buf, srcaddr->buf, srcaddr->len);
19357c478bd9Sstevel@tonic-gate RPCLOG(2, "connmgr_get: call going out on %p\n",
19367c478bd9Sstevel@tonic-gate (void *)lru_entry);
1937d3d50737SRafael Vanoni lru_entry->x_time = ddi_get_lbolt();
19387c478bd9Sstevel@tonic-gate CONN_HOLD(lru_entry);
193981dbf0b5SDai Ngo
194081dbf0b5SDai Ngo if ((i > 1) && (prev != &cm_hd)) {
194181dbf0b5SDai Ngo /*
194281dbf0b5SDai Ngo * remove and re-insert entry at head of list.
194381dbf0b5SDai Ngo */
194481dbf0b5SDai Ngo *prev = lru_entry->x_next;
194581dbf0b5SDai Ngo lru_entry->x_next = cm_hd;
194681dbf0b5SDai Ngo cm_hd = lru_entry;
194781dbf0b5SDai Ngo }
194881dbf0b5SDai Ngo
19497c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
19507c478bd9Sstevel@tonic-gate return (lru_entry);
19517c478bd9Sstevel@tonic-gate }
19527c478bd9Sstevel@tonic-gate
19537c478bd9Sstevel@tonic-gate } else {
19547c478bd9Sstevel@tonic-gate /*
19557c478bd9Sstevel@tonic-gate * This is the retry case (retryaddr != NULL). Retries must
19567c478bd9Sstevel@tonic-gate * be sent on the same source port as the original call.
19577c478bd9Sstevel@tonic-gate */
19587c478bd9Sstevel@tonic-gate
19597c478bd9Sstevel@tonic-gate /*
19607c478bd9Sstevel@tonic-gate * Walk the list looking for a connection with a source address
19617c478bd9Sstevel@tonic-gate * that matches the retry address.
19627c478bd9Sstevel@tonic-gate */
19633807480aSGerald Thornbrugh start_retry_loop:
19647c478bd9Sstevel@tonic-gate cmp = &cm_hd;
19657c478bd9Sstevel@tonic-gate while ((cm_entry = *cmp) != NULL) {
19667c478bd9Sstevel@tonic-gate ASSERT(cm_entry != cm_entry->x_next);
19673807480aSGerald Thornbrugh
19683807480aSGerald Thornbrugh /*
19693807480aSGerald Thornbrugh * determine if this connection matches the passed
19703807480aSGerald Thornbrugh * in retry address. If it does not match, advance
19713807480aSGerald Thornbrugh * to the next element on the list.
19723807480aSGerald Thornbrugh */
19737c478bd9Sstevel@tonic-gate if (zoneid != cm_entry->x_zoneid ||
19747c478bd9Sstevel@tonic-gate device != cm_entry->x_rdev ||
19757c478bd9Sstevel@tonic-gate retryaddr->len != cm_entry->x_src.len ||
19767c478bd9Sstevel@tonic-gate bcmp(retryaddr->buf, cm_entry->x_src.buf,
19777c478bd9Sstevel@tonic-gate retryaddr->len) != 0) {
19787c478bd9Sstevel@tonic-gate cmp = &cm_entry->x_next;
19797c478bd9Sstevel@tonic-gate continue;
19807c478bd9Sstevel@tonic-gate }
19813807480aSGerald Thornbrugh /*
19823807480aSGerald Thornbrugh * Garbage collect conections that are marked
19833807480aSGerald Thornbrugh * for needs disconnect.
19843807480aSGerald Thornbrugh */
19853807480aSGerald Thornbrugh if (cm_entry->x_needdis) {
19863807480aSGerald Thornbrugh CONN_HOLD(cm_entry);
19873807480aSGerald Thornbrugh connmgr_dis_and_wait(cm_entry);
19883807480aSGerald Thornbrugh connmgr_release(cm_entry);
19893807480aSGerald Thornbrugh /*
19903807480aSGerald Thornbrugh * connmgr_lock could have been
19913807480aSGerald Thornbrugh * dropped for the disconnect
19923807480aSGerald Thornbrugh * processing so start over.
19933807480aSGerald Thornbrugh */
19943807480aSGerald Thornbrugh goto start_retry_loop;
19953807480aSGerald Thornbrugh }
19963807480aSGerald Thornbrugh /*
19973807480aSGerald Thornbrugh * Garbage collect the dead connections that have
19983807480aSGerald Thornbrugh * no threads working on them.
19993807480aSGerald Thornbrugh */
20003807480aSGerald Thornbrugh if ((cm_entry->x_state_flags & (X_DEAD|X_THREAD)) ==
20013807480aSGerald Thornbrugh X_DEAD) {
20023807480aSGerald Thornbrugh mutex_enter(&cm_entry->x_lock);
20033807480aSGerald Thornbrugh if (cm_entry->x_ref != 0) {
20043807480aSGerald Thornbrugh /*
20053807480aSGerald Thornbrugh * Currently in use.
20063807480aSGerald Thornbrugh * Cleanup later.
20073807480aSGerald Thornbrugh */
20083807480aSGerald Thornbrugh cmp = &cm_entry->x_next;
20093807480aSGerald Thornbrugh mutex_exit(&cm_entry->x_lock);
20103807480aSGerald Thornbrugh continue;
20113807480aSGerald Thornbrugh }
20123807480aSGerald Thornbrugh mutex_exit(&cm_entry->x_lock);
20133807480aSGerald Thornbrugh *cmp = cm_entry->x_next;
20143807480aSGerald Thornbrugh mutex_exit(&connmgr_lock);
20153807480aSGerald Thornbrugh connmgr_close(cm_entry);
20163807480aSGerald Thornbrugh mutex_enter(&connmgr_lock);
20173807480aSGerald Thornbrugh goto start_retry_loop;
20183807480aSGerald Thornbrugh }
20197c478bd9Sstevel@tonic-gate
20207c478bd9Sstevel@tonic-gate /*
20217c478bd9Sstevel@tonic-gate * Sanity check: if the connection with our source
20227c478bd9Sstevel@tonic-gate * port is going to some other server, something went
20237c478bd9Sstevel@tonic-gate * wrong, as we never delete connections (i.e. release
20247c478bd9Sstevel@tonic-gate * ports) unless they have been idle. In this case,
20257c478bd9Sstevel@tonic-gate * it is probably better to send the call out using
20267c478bd9Sstevel@tonic-gate * a new source address than to fail it altogether,
20277c478bd9Sstevel@tonic-gate * since that port may never be released.
20287c478bd9Sstevel@tonic-gate */
20297c478bd9Sstevel@tonic-gate if (destaddr->len != cm_entry->x_server.len ||
20307c478bd9Sstevel@tonic-gate bcmp(destaddr->buf, cm_entry->x_server.buf,
20317c478bd9Sstevel@tonic-gate destaddr->len) != 0) {
20327c478bd9Sstevel@tonic-gate RPCLOG(1, "connmgr_get: tiptr %p"
20337c478bd9Sstevel@tonic-gate " is going to a different server"
20347c478bd9Sstevel@tonic-gate " with the port that belongs"
20357c478bd9Sstevel@tonic-gate " to us!\n", (void *)cm_entry->x_tiptr);
20367c478bd9Sstevel@tonic-gate retryaddr = NULL;
20377c478bd9Sstevel@tonic-gate goto use_new_conn;
20387c478bd9Sstevel@tonic-gate }
20397c478bd9Sstevel@tonic-gate
20407c478bd9Sstevel@tonic-gate /*
20417c478bd9Sstevel@tonic-gate * If the connection of interest is not connected and we
20427c478bd9Sstevel@tonic-gate * can't reconnect it, then the server is probably
20437c478bd9Sstevel@tonic-gate * still down. Return NULL to the caller and let it
20447c478bd9Sstevel@tonic-gate * retry later if it wants to. We have a delay so the
20457c478bd9Sstevel@tonic-gate * machine doesn't go into a tight retry loop. If the
20467c478bd9Sstevel@tonic-gate * entry was already connected, or the reconnected was
20477c478bd9Sstevel@tonic-gate * successful, return this entry.
20487c478bd9Sstevel@tonic-gate */
20497c478bd9Sstevel@tonic-gate if (cm_entry->x_connected == FALSE) {
20507c478bd9Sstevel@tonic-gate return (connmgr_wrapconnect(cm_entry,
20517c478bd9Sstevel@tonic-gate waitp, destaddr, addrfmly, NULL,
2052de8c4a14SErik Nordmark rpcerr, TRUE, nosignal, cr));
20537c478bd9Sstevel@tonic-gate } else {
20547c478bd9Sstevel@tonic-gate CONN_HOLD(cm_entry);
20557c478bd9Sstevel@tonic-gate
2056d3d50737SRafael Vanoni cm_entry->x_time = ddi_get_lbolt();
20577c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
20587c478bd9Sstevel@tonic-gate RPCLOG(2, "connmgr_get: found old "
20597c478bd9Sstevel@tonic-gate "transport %p for retry\n",
20607c478bd9Sstevel@tonic-gate (void *)cm_entry);
20617c478bd9Sstevel@tonic-gate return (cm_entry);
20627c478bd9Sstevel@tonic-gate }
20637c478bd9Sstevel@tonic-gate }
20647c478bd9Sstevel@tonic-gate
20657c478bd9Sstevel@tonic-gate /*
20667c478bd9Sstevel@tonic-gate * We cannot find an entry in the list for this retry.
20677c478bd9Sstevel@tonic-gate * Either the entry has been removed temporarily to be
20687c478bd9Sstevel@tonic-gate * reconnected by another thread, or the original call
20697c478bd9Sstevel@tonic-gate * got a port but never got connected,
20707c478bd9Sstevel@tonic-gate * and hence the transport never got put in the
20717c478bd9Sstevel@tonic-gate * list. Fall through to the "create new connection" code -
20727c478bd9Sstevel@tonic-gate * the former case will fail there trying to rebind the port,
20737c478bd9Sstevel@tonic-gate * and the later case (and any other pathological cases) will
20747c478bd9Sstevel@tonic-gate * rebind and reconnect and not hang the client machine.
20757c478bd9Sstevel@tonic-gate */
20767c478bd9Sstevel@tonic-gate RPCLOG0(8, "connmgr_get: no entry in list for retry\n");
20777c478bd9Sstevel@tonic-gate }
20787c478bd9Sstevel@tonic-gate /*
20797c478bd9Sstevel@tonic-gate * Set up a transport entry in the connection manager's list.
20807c478bd9Sstevel@tonic-gate */
20817c478bd9Sstevel@tonic-gate cm_entry = (struct cm_xprt *)
20827c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (struct cm_xprt), KM_SLEEP);
20837c478bd9Sstevel@tonic-gate
20847c478bd9Sstevel@tonic-gate cm_entry->x_server.buf = kmem_zalloc(destaddr->len, KM_SLEEP);
20857c478bd9Sstevel@tonic-gate bcopy(destaddr->buf, cm_entry->x_server.buf, destaddr->len);
20867c478bd9Sstevel@tonic-gate cm_entry->x_server.len = cm_entry->x_server.maxlen = destaddr->len;
20877c478bd9Sstevel@tonic-gate
20887c478bd9Sstevel@tonic-gate cm_entry->x_state_flags = X_THREAD;
20897c478bd9Sstevel@tonic-gate cm_entry->x_ref = 1;
20907c478bd9Sstevel@tonic-gate cm_entry->x_family = addrfmly;
20917c478bd9Sstevel@tonic-gate cm_entry->x_rdev = device;
20927c478bd9Sstevel@tonic-gate cm_entry->x_zoneid = zoneid;
20937c478bd9Sstevel@tonic-gate mutex_init(&cm_entry->x_lock, NULL, MUTEX_DEFAULT, NULL);
20947c478bd9Sstevel@tonic-gate cv_init(&cm_entry->x_cv, NULL, CV_DEFAULT, NULL);
20957c478bd9Sstevel@tonic-gate cv_init(&cm_entry->x_conn_cv, NULL, CV_DEFAULT, NULL);
20967c478bd9Sstevel@tonic-gate cv_init(&cm_entry->x_dis_cv, NULL, CV_DEFAULT, NULL);
20977c478bd9Sstevel@tonic-gate
20987c478bd9Sstevel@tonic-gate /*
20997c478bd9Sstevel@tonic-gate * Note that we add this partially initialized entry to the
21007c478bd9Sstevel@tonic-gate * connection list. This is so that we don't have connections to
21017c478bd9Sstevel@tonic-gate * the same server.
21027c478bd9Sstevel@tonic-gate *
21037c478bd9Sstevel@tonic-gate * Note that x_src is not initialized at this point. This is because
21047c478bd9Sstevel@tonic-gate * retryaddr might be NULL in which case x_src is whatever
21057c478bd9Sstevel@tonic-gate * t_kbind/bindresvport gives us. If another thread wants a
21067c478bd9Sstevel@tonic-gate * connection to the same server, seemingly we have an issue, but we
21077c478bd9Sstevel@tonic-gate * don't. If the other thread comes in with retryaddr == NULL, then it
21087c478bd9Sstevel@tonic-gate * will never look at x_src, and it will end up waiting in
21097c478bd9Sstevel@tonic-gate * connmgr_cwait() for the first thread to finish the connection
21107c478bd9Sstevel@tonic-gate * attempt. If the other thread comes in with retryaddr != NULL, then
21117c478bd9Sstevel@tonic-gate * that means there was a request sent on a connection, in which case
21127c478bd9Sstevel@tonic-gate * the the connection should already exist. Thus the first thread
21137c478bd9Sstevel@tonic-gate * never gets here ... it finds the connection it its server in the
21147c478bd9Sstevel@tonic-gate * connection list.
21157c478bd9Sstevel@tonic-gate *
21167c478bd9Sstevel@tonic-gate * But even if theory is wrong, in the retryaddr != NULL case, the 2nd
21177c478bd9Sstevel@tonic-gate * thread will skip us because x_src.len == 0.
21187c478bd9Sstevel@tonic-gate */
21197c478bd9Sstevel@tonic-gate cm_entry->x_next = cm_hd;
21207c478bd9Sstevel@tonic-gate cm_hd = cm_entry;
21217c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
21227c478bd9Sstevel@tonic-gate
21237c478bd9Sstevel@tonic-gate /*
21247c478bd9Sstevel@tonic-gate * Either we didn't find an entry to the server of interest, or we
21257c478bd9Sstevel@tonic-gate * don't have the maximum number of connections to that server -
21267c478bd9Sstevel@tonic-gate * create a new connection.
21277c478bd9Sstevel@tonic-gate */
21287c478bd9Sstevel@tonic-gate RPCLOG0(8, "connmgr_get: creating new connection\n");
21297c478bd9Sstevel@tonic-gate rpcerr->re_status = RPC_TLIERROR;
21307c478bd9Sstevel@tonic-gate
213145916cd2Sjpk i = t_kopen(NULL, device, FREAD|FWRITE|FNDELAY, &tiptr, zone_kcred());
21327c478bd9Sstevel@tonic-gate if (i) {
21337c478bd9Sstevel@tonic-gate RPCLOG(1, "connmgr_get: can't open cots device, error %d\n", i);
21347c478bd9Sstevel@tonic-gate rpcerr->re_errno = i;
21357c478bd9Sstevel@tonic-gate connmgr_cancelconn(cm_entry);
21367c478bd9Sstevel@tonic-gate return (NULL);
21377c478bd9Sstevel@tonic-gate }
21387c478bd9Sstevel@tonic-gate rpc_poptimod(tiptr->fp->f_vnode);
21397c478bd9Sstevel@tonic-gate
21407c478bd9Sstevel@tonic-gate if (i = strioctl(tiptr->fp->f_vnode, I_PUSH, (intptr_t)"rpcmod", 0,
21417c478bd9Sstevel@tonic-gate K_TO_K, kcred, &retval)) {
21427c478bd9Sstevel@tonic-gate RPCLOG(1, "connmgr_get: can't push cots module, %d\n", i);
21437c478bd9Sstevel@tonic-gate (void) t_kclose(tiptr, 1);
21447c478bd9Sstevel@tonic-gate rpcerr->re_errno = i;
21457c478bd9Sstevel@tonic-gate connmgr_cancelconn(cm_entry);
21467c478bd9Sstevel@tonic-gate return (NULL);
21477c478bd9Sstevel@tonic-gate }
21487c478bd9Sstevel@tonic-gate
21497c478bd9Sstevel@tonic-gate if (i = strioctl(tiptr->fp->f_vnode, RPC_CLIENT, 0, 0, K_TO_K,
21507c478bd9Sstevel@tonic-gate kcred, &retval)) {
21517c478bd9Sstevel@tonic-gate RPCLOG(1, "connmgr_get: can't set client status with cots "
21527c478bd9Sstevel@tonic-gate "module, %d\n", i);
21537c478bd9Sstevel@tonic-gate (void) t_kclose(tiptr, 1);
21547c478bd9Sstevel@tonic-gate rpcerr->re_errno = i;
21557c478bd9Sstevel@tonic-gate connmgr_cancelconn(cm_entry);
21567c478bd9Sstevel@tonic-gate return (NULL);
21577c478bd9Sstevel@tonic-gate }
21587c478bd9Sstevel@tonic-gate
21597c478bd9Sstevel@tonic-gate mutex_enter(&connmgr_lock);
21607c478bd9Sstevel@tonic-gate
21617c478bd9Sstevel@tonic-gate wq = tiptr->fp->f_vnode->v_stream->sd_wrq->q_next;
21627c478bd9Sstevel@tonic-gate cm_entry->x_wq = wq;
21637c478bd9Sstevel@tonic-gate
21647c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
21657c478bd9Sstevel@tonic-gate
21667c478bd9Sstevel@tonic-gate if (i = strioctl(tiptr->fp->f_vnode, I_PUSH, (intptr_t)"timod", 0,
21677c478bd9Sstevel@tonic-gate K_TO_K, kcred, &retval)) {
21687c478bd9Sstevel@tonic-gate RPCLOG(1, "connmgr_get: can't push timod, %d\n", i);
21697c478bd9Sstevel@tonic-gate (void) t_kclose(tiptr, 1);
21707c478bd9Sstevel@tonic-gate rpcerr->re_errno = i;
21717c478bd9Sstevel@tonic-gate connmgr_cancelconn(cm_entry);
21727c478bd9Sstevel@tonic-gate return (NULL);
21737c478bd9Sstevel@tonic-gate }
21747c478bd9Sstevel@tonic-gate
21757c478bd9Sstevel@tonic-gate /*
21767c478bd9Sstevel@tonic-gate * If the caller has not specified reserved port usage then
21777c478bd9Sstevel@tonic-gate * take the system default.
21787c478bd9Sstevel@tonic-gate */
21797c478bd9Sstevel@tonic-gate if (useresvport == -1)
21807c478bd9Sstevel@tonic-gate useresvport = clnt_cots_do_bindresvport;
21817c478bd9Sstevel@tonic-gate
21827c478bd9Sstevel@tonic-gate if ((useresvport || retryaddr != NULL) &&
21837c478bd9Sstevel@tonic-gate (addrfmly == AF_INET || addrfmly == AF_INET6)) {
21847c478bd9Sstevel@tonic-gate bool_t alloc_src = FALSE;
21857c478bd9Sstevel@tonic-gate
21867c478bd9Sstevel@tonic-gate if (srcaddr->len != destaddr->len) {
21877c478bd9Sstevel@tonic-gate kmem_free(srcaddr->buf, srcaddr->maxlen);
21887c478bd9Sstevel@tonic-gate srcaddr->buf = kmem_zalloc(destaddr->len, KM_SLEEP);
21897c478bd9Sstevel@tonic-gate srcaddr->maxlen = destaddr->len;
21907c478bd9Sstevel@tonic-gate srcaddr->len = destaddr->len;
21917c478bd9Sstevel@tonic-gate alloc_src = TRUE;
21927c478bd9Sstevel@tonic-gate }
21937c478bd9Sstevel@tonic-gate
21947c478bd9Sstevel@tonic-gate if ((i = bindresvport(tiptr, retryaddr, srcaddr, TRUE)) != 0) {
21957c478bd9Sstevel@tonic-gate (void) t_kclose(tiptr, 1);
21967c478bd9Sstevel@tonic-gate RPCLOG(1, "connmgr_get: couldn't bind, retryaddr: "
21977c478bd9Sstevel@tonic-gate "%p\n", (void *)retryaddr);
21987c478bd9Sstevel@tonic-gate
21997c478bd9Sstevel@tonic-gate /*
22007c478bd9Sstevel@tonic-gate * 1225408: If we allocated a source address, then it
22017c478bd9Sstevel@tonic-gate * is either garbage or all zeroes. In that case
22027c478bd9Sstevel@tonic-gate * we need to clear srcaddr.
22037c478bd9Sstevel@tonic-gate */
22047c478bd9Sstevel@tonic-gate if (alloc_src == TRUE) {
22057c478bd9Sstevel@tonic-gate kmem_free(srcaddr->buf, srcaddr->maxlen);
22067c478bd9Sstevel@tonic-gate srcaddr->maxlen = srcaddr->len = 0;
22077c478bd9Sstevel@tonic-gate srcaddr->buf = NULL;
22087c478bd9Sstevel@tonic-gate }
22097c478bd9Sstevel@tonic-gate rpcerr->re_errno = i;
22107c478bd9Sstevel@tonic-gate connmgr_cancelconn(cm_entry);
22117c478bd9Sstevel@tonic-gate return (NULL);
22127c478bd9Sstevel@tonic-gate }
22137c478bd9Sstevel@tonic-gate } else {
22147c478bd9Sstevel@tonic-gate if ((i = t_kbind(tiptr, NULL, NULL)) != 0) {
22157c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_cots_kcreate: t_kbind: %d\n", i);
22167c478bd9Sstevel@tonic-gate (void) t_kclose(tiptr, 1);
22177c478bd9Sstevel@tonic-gate rpcerr->re_errno = i;
22187c478bd9Sstevel@tonic-gate connmgr_cancelconn(cm_entry);
22197c478bd9Sstevel@tonic-gate return (NULL);
22207c478bd9Sstevel@tonic-gate }
22217c478bd9Sstevel@tonic-gate }
22227c478bd9Sstevel@tonic-gate
22237c478bd9Sstevel@tonic-gate {
22247c478bd9Sstevel@tonic-gate /*
22257c478bd9Sstevel@tonic-gate * Keep the kernel stack lean. Don't move this call
22267c478bd9Sstevel@tonic-gate * declaration to the top of this function because a
22277c478bd9Sstevel@tonic-gate * call is declared in connmgr_wrapconnect()
22287c478bd9Sstevel@tonic-gate */
22297c478bd9Sstevel@tonic-gate calllist_t call;
22307c478bd9Sstevel@tonic-gate
22317c478bd9Sstevel@tonic-gate bzero(&call, sizeof (call));
22327c478bd9Sstevel@tonic-gate cv_init(&call.call_cv, NULL, CV_DEFAULT, NULL);
22337c478bd9Sstevel@tonic-gate
22347c478bd9Sstevel@tonic-gate /*
22357c478bd9Sstevel@tonic-gate * This is a bound end-point so don't close it's stream.
22367c478bd9Sstevel@tonic-gate */
22377c478bd9Sstevel@tonic-gate connected = connmgr_connect(cm_entry, wq, destaddr, addrfmly,
2238de8c4a14SErik Nordmark &call, &tidu_size, FALSE, waitp, nosignal, cr);
22397c478bd9Sstevel@tonic-gate *rpcerr = call.call_err;
22407c478bd9Sstevel@tonic-gate cv_destroy(&call.call_cv);
22417c478bd9Sstevel@tonic-gate
22427c478bd9Sstevel@tonic-gate }
22437c478bd9Sstevel@tonic-gate
22447c478bd9Sstevel@tonic-gate mutex_enter(&connmgr_lock);
22457c478bd9Sstevel@tonic-gate
22467c478bd9Sstevel@tonic-gate /*
22477c478bd9Sstevel@tonic-gate * Set up a transport entry in the connection manager's list.
22487c478bd9Sstevel@tonic-gate */
22497c478bd9Sstevel@tonic-gate cm_entry->x_src.buf = kmem_zalloc(srcaddr->len, KM_SLEEP);
22507c478bd9Sstevel@tonic-gate bcopy(srcaddr->buf, cm_entry->x_src.buf, srcaddr->len);
22517c478bd9Sstevel@tonic-gate cm_entry->x_src.len = cm_entry->x_src.maxlen = srcaddr->len;
22527c478bd9Sstevel@tonic-gate
22537c478bd9Sstevel@tonic-gate cm_entry->x_tiptr = tiptr;
2254d3d50737SRafael Vanoni cm_entry->x_time = ddi_get_lbolt();
22557c478bd9Sstevel@tonic-gate
22567c478bd9Sstevel@tonic-gate if (tiptr->tp_info.servtype == T_COTS_ORD)
22577c478bd9Sstevel@tonic-gate cm_entry->x_ordrel = TRUE;
22587c478bd9Sstevel@tonic-gate else
22597c478bd9Sstevel@tonic-gate cm_entry->x_ordrel = FALSE;
22607c478bd9Sstevel@tonic-gate
22617c478bd9Sstevel@tonic-gate cm_entry->x_tidu_size = tidu_size;
22627c478bd9Sstevel@tonic-gate
2263af41c4bfSvv149972 if (cm_entry->x_early_disc) {
2264af41c4bfSvv149972 /*
2265af41c4bfSvv149972 * We need to check if a disconnect request has come
2266af41c4bfSvv149972 * while we are connected, if so, then we need to
2267af41c4bfSvv149972 * set rpcerr->re_status appropriately before returning
2268af41c4bfSvv149972 * NULL to caller.
2269af41c4bfSvv149972 */
2270af41c4bfSvv149972 if (rpcerr->re_status == RPC_SUCCESS)
2271af41c4bfSvv149972 rpcerr->re_status = RPC_XPRTFAILED;
22727c478bd9Sstevel@tonic-gate cm_entry->x_connected = FALSE;
2273af41c4bfSvv149972 } else
22747c478bd9Sstevel@tonic-gate cm_entry->x_connected = connected;
22757c478bd9Sstevel@tonic-gate
22767c478bd9Sstevel@tonic-gate /*
22777c478bd9Sstevel@tonic-gate * There could be a discrepancy here such that
22787c478bd9Sstevel@tonic-gate * x_early_disc is TRUE yet connected is TRUE as well
22797c478bd9Sstevel@tonic-gate * and the connection is actually connected. In that case
22807c478bd9Sstevel@tonic-gate * lets be conservative and declare the connection as not
22817c478bd9Sstevel@tonic-gate * connected.
22827c478bd9Sstevel@tonic-gate */
22837c478bd9Sstevel@tonic-gate cm_entry->x_early_disc = FALSE;
22847c478bd9Sstevel@tonic-gate cm_entry->x_needdis = (cm_entry->x_connected == FALSE);
2285d3d50737SRafael Vanoni cm_entry->x_ctime = ddi_get_lbolt();
22867c478bd9Sstevel@tonic-gate
22877c478bd9Sstevel@tonic-gate /*
22887c478bd9Sstevel@tonic-gate * Notify any threads waiting that the connection attempt is done.
22897c478bd9Sstevel@tonic-gate */
22907c478bd9Sstevel@tonic-gate cm_entry->x_thread = FALSE;
22917c478bd9Sstevel@tonic-gate cv_broadcast(&cm_entry->x_conn_cv);
22927c478bd9Sstevel@tonic-gate
22937c478bd9Sstevel@tonic-gate if (cm_entry->x_connected == FALSE) {
2294af41c4bfSvv149972 mutex_exit(&connmgr_lock);
22957c478bd9Sstevel@tonic-gate connmgr_release(cm_entry);
22967c478bd9Sstevel@tonic-gate return (NULL);
22977c478bd9Sstevel@tonic-gate }
2298af41c4bfSvv149972
2299af41c4bfSvv149972 mutex_exit(&connmgr_lock);
2300af41c4bfSvv149972
23017c478bd9Sstevel@tonic-gate return (cm_entry);
23027c478bd9Sstevel@tonic-gate }
23037c478bd9Sstevel@tonic-gate
23047c478bd9Sstevel@tonic-gate /*
23057c478bd9Sstevel@tonic-gate * Keep the cm_xprt entry on the connecton list when making a connection. This
23067c478bd9Sstevel@tonic-gate * is to prevent multiple connections to a slow server from appearing.
23077c478bd9Sstevel@tonic-gate * We use the bit field x_thread to tell if a thread is doing a connection
23087c478bd9Sstevel@tonic-gate * which keeps other interested threads from messing with connection.
23097c478bd9Sstevel@tonic-gate * Those other threads just wait if x_thread is set.
23107c478bd9Sstevel@tonic-gate *
23117c478bd9Sstevel@tonic-gate * If x_thread is not set, then we do the actual work of connecting via
23127c478bd9Sstevel@tonic-gate * connmgr_connect().
23137c478bd9Sstevel@tonic-gate *
23147c478bd9Sstevel@tonic-gate * mutex convention: called with connmgr_lock held, returns with it released.
23157c478bd9Sstevel@tonic-gate */
23167c478bd9Sstevel@tonic-gate static struct cm_xprt *
connmgr_wrapconnect(struct cm_xprt * cm_entry,const struct timeval * waitp,struct netbuf * destaddr,int addrfmly,struct netbuf * srcaddr,struct rpc_err * rpcerr,bool_t reconnect,bool_t nosignal,cred_t * cr)23177c478bd9Sstevel@tonic-gate connmgr_wrapconnect(
23187c478bd9Sstevel@tonic-gate struct cm_xprt *cm_entry,
23197c478bd9Sstevel@tonic-gate const struct timeval *waitp,
23207c478bd9Sstevel@tonic-gate struct netbuf *destaddr,
23217c478bd9Sstevel@tonic-gate int addrfmly,
23227c478bd9Sstevel@tonic-gate struct netbuf *srcaddr,
23237c478bd9Sstevel@tonic-gate struct rpc_err *rpcerr,
23247c478bd9Sstevel@tonic-gate bool_t reconnect,
2325de8c4a14SErik Nordmark bool_t nosignal,
2326de8c4a14SErik Nordmark cred_t *cr)
23277c478bd9Sstevel@tonic-gate {
23287c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&connmgr_lock));
23297c478bd9Sstevel@tonic-gate /*
23307c478bd9Sstevel@tonic-gate * Hold this entry as we are about to drop connmgr_lock.
23317c478bd9Sstevel@tonic-gate */
23327c478bd9Sstevel@tonic-gate CONN_HOLD(cm_entry);
23337c478bd9Sstevel@tonic-gate
23347c478bd9Sstevel@tonic-gate /*
23357c478bd9Sstevel@tonic-gate * If there is a thread already making a connection for us, then
23367c478bd9Sstevel@tonic-gate * wait for it to complete the connection.
23377c478bd9Sstevel@tonic-gate */
23387c478bd9Sstevel@tonic-gate if (cm_entry->x_thread == TRUE) {
23397c478bd9Sstevel@tonic-gate rpcerr->re_status = connmgr_cwait(cm_entry, waitp, nosignal);
23407c478bd9Sstevel@tonic-gate
23417c478bd9Sstevel@tonic-gate if (rpcerr->re_status != RPC_SUCCESS) {
23427c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
23437c478bd9Sstevel@tonic-gate connmgr_release(cm_entry);
23447c478bd9Sstevel@tonic-gate return (NULL);
23457c478bd9Sstevel@tonic-gate }
23467c478bd9Sstevel@tonic-gate } else {
23477c478bd9Sstevel@tonic-gate bool_t connected;
23487c478bd9Sstevel@tonic-gate calllist_t call;
23497c478bd9Sstevel@tonic-gate
23507c478bd9Sstevel@tonic-gate cm_entry->x_thread = TRUE;
23517c478bd9Sstevel@tonic-gate
23527c478bd9Sstevel@tonic-gate while (cm_entry->x_needrel == TRUE) {
23537c478bd9Sstevel@tonic-gate cm_entry->x_needrel = FALSE;
23547c478bd9Sstevel@tonic-gate
23557c478bd9Sstevel@tonic-gate connmgr_sndrel(cm_entry);
23567c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000));
23577c478bd9Sstevel@tonic-gate
23587c478bd9Sstevel@tonic-gate mutex_enter(&connmgr_lock);
23597c478bd9Sstevel@tonic-gate }
23607c478bd9Sstevel@tonic-gate
23617c478bd9Sstevel@tonic-gate /*
23627c478bd9Sstevel@tonic-gate * If we need to send a T_DISCON_REQ, send one.
23637c478bd9Sstevel@tonic-gate */
23647c478bd9Sstevel@tonic-gate connmgr_dis_and_wait(cm_entry);
23657c478bd9Sstevel@tonic-gate
23667c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
23677c478bd9Sstevel@tonic-gate
23687c478bd9Sstevel@tonic-gate bzero(&call, sizeof (call));
23697c478bd9Sstevel@tonic-gate cv_init(&call.call_cv, NULL, CV_DEFAULT, NULL);
23707c478bd9Sstevel@tonic-gate
23717c478bd9Sstevel@tonic-gate connected = connmgr_connect(cm_entry, cm_entry->x_wq,
23728ffff9fdSgt29601 destaddr, addrfmly, &call, &cm_entry->x_tidu_size,
2373de8c4a14SErik Nordmark reconnect, waitp, nosignal, cr);
23747c478bd9Sstevel@tonic-gate
23757c478bd9Sstevel@tonic-gate *rpcerr = call.call_err;
23767c478bd9Sstevel@tonic-gate cv_destroy(&call.call_cv);
23777c478bd9Sstevel@tonic-gate
23787c478bd9Sstevel@tonic-gate mutex_enter(&connmgr_lock);
23797c478bd9Sstevel@tonic-gate
23807c478bd9Sstevel@tonic-gate
2381af41c4bfSvv149972 if (cm_entry->x_early_disc) {
2382af41c4bfSvv149972 /*
2383af41c4bfSvv149972 * We need to check if a disconnect request has come
2384af41c4bfSvv149972 * while we are connected, if so, then we need to
2385af41c4bfSvv149972 * set rpcerr->re_status appropriately before returning
2386af41c4bfSvv149972 * NULL to caller.
2387af41c4bfSvv149972 */
2388af41c4bfSvv149972 if (rpcerr->re_status == RPC_SUCCESS)
2389af41c4bfSvv149972 rpcerr->re_status = RPC_XPRTFAILED;
23907c478bd9Sstevel@tonic-gate cm_entry->x_connected = FALSE;
2391af41c4bfSvv149972 } else
23927c478bd9Sstevel@tonic-gate cm_entry->x_connected = connected;
23937c478bd9Sstevel@tonic-gate
23947c478bd9Sstevel@tonic-gate /*
23957c478bd9Sstevel@tonic-gate * There could be a discrepancy here such that
23967c478bd9Sstevel@tonic-gate * x_early_disc is TRUE yet connected is TRUE as well
23977c478bd9Sstevel@tonic-gate * and the connection is actually connected. In that case
23987c478bd9Sstevel@tonic-gate * lets be conservative and declare the connection as not
23997c478bd9Sstevel@tonic-gate * connected.
24007c478bd9Sstevel@tonic-gate */
24017c478bd9Sstevel@tonic-gate
24027c478bd9Sstevel@tonic-gate cm_entry->x_early_disc = FALSE;
24037c478bd9Sstevel@tonic-gate cm_entry->x_needdis = (cm_entry->x_connected == FALSE);
24047c478bd9Sstevel@tonic-gate
24057c478bd9Sstevel@tonic-gate
24067c478bd9Sstevel@tonic-gate /*
24077c478bd9Sstevel@tonic-gate * connmgr_connect() may have given up before the connection
24087c478bd9Sstevel@tonic-gate * actually timed out. So ensure that before the next
24097c478bd9Sstevel@tonic-gate * connection attempt we do a disconnect.
24107c478bd9Sstevel@tonic-gate */
2411d3d50737SRafael Vanoni cm_entry->x_ctime = ddi_get_lbolt();
24127c478bd9Sstevel@tonic-gate cm_entry->x_thread = FALSE;
24137c478bd9Sstevel@tonic-gate
24147c478bd9Sstevel@tonic-gate cv_broadcast(&cm_entry->x_conn_cv);
24157c478bd9Sstevel@tonic-gate
24167c478bd9Sstevel@tonic-gate if (cm_entry->x_connected == FALSE) {
24177c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
24187c478bd9Sstevel@tonic-gate connmgr_release(cm_entry);
24197c478bd9Sstevel@tonic-gate return (NULL);
24207c478bd9Sstevel@tonic-gate }
24217c478bd9Sstevel@tonic-gate }
24227c478bd9Sstevel@tonic-gate
24237c478bd9Sstevel@tonic-gate if (srcaddr != NULL) {
24247c478bd9Sstevel@tonic-gate /*
24257c478bd9Sstevel@tonic-gate * Copy into the handle the
24267c478bd9Sstevel@tonic-gate * source address of the
24277c478bd9Sstevel@tonic-gate * connection, which we will use
24287c478bd9Sstevel@tonic-gate * in case of a later retry.
24297c478bd9Sstevel@tonic-gate */
24307c478bd9Sstevel@tonic-gate if (srcaddr->len != cm_entry->x_src.len) {
24317c478bd9Sstevel@tonic-gate if (srcaddr->maxlen > 0)
24327c478bd9Sstevel@tonic-gate kmem_free(srcaddr->buf, srcaddr->maxlen);
24337c478bd9Sstevel@tonic-gate srcaddr->buf = kmem_zalloc(cm_entry->x_src.len,
24347c478bd9Sstevel@tonic-gate KM_SLEEP);
24357c478bd9Sstevel@tonic-gate srcaddr->maxlen = srcaddr->len =
24367c478bd9Sstevel@tonic-gate cm_entry->x_src.len;
24377c478bd9Sstevel@tonic-gate }
24387c478bd9Sstevel@tonic-gate bcopy(cm_entry->x_src.buf, srcaddr->buf, srcaddr->len);
24397c478bd9Sstevel@tonic-gate }
2440d3d50737SRafael Vanoni cm_entry->x_time = ddi_get_lbolt();
24417c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
24427c478bd9Sstevel@tonic-gate return (cm_entry);
24437c478bd9Sstevel@tonic-gate }
24447c478bd9Sstevel@tonic-gate
24457c478bd9Sstevel@tonic-gate /*
24467c478bd9Sstevel@tonic-gate * If we need to send a T_DISCON_REQ, send one.
24477c478bd9Sstevel@tonic-gate */
24487c478bd9Sstevel@tonic-gate static void
connmgr_dis_and_wait(struct cm_xprt * cm_entry)24497c478bd9Sstevel@tonic-gate connmgr_dis_and_wait(struct cm_xprt *cm_entry)
24507c478bd9Sstevel@tonic-gate {
24517c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&connmgr_lock));
24527c478bd9Sstevel@tonic-gate for (;;) {
24537c478bd9Sstevel@tonic-gate while (cm_entry->x_needdis == TRUE) {
24547c478bd9Sstevel@tonic-gate RPCLOG(8, "connmgr_dis_and_wait: need "
24557c478bd9Sstevel@tonic-gate "T_DISCON_REQ for connection 0x%p\n",
24567c478bd9Sstevel@tonic-gate (void *)cm_entry);
24577c478bd9Sstevel@tonic-gate cm_entry->x_needdis = FALSE;
24587c478bd9Sstevel@tonic-gate cm_entry->x_waitdis = TRUE;
24597c478bd9Sstevel@tonic-gate
24607c478bd9Sstevel@tonic-gate connmgr_snddis(cm_entry);
24617c478bd9Sstevel@tonic-gate
24627c478bd9Sstevel@tonic-gate mutex_enter(&connmgr_lock);
24637c478bd9Sstevel@tonic-gate }
24647c478bd9Sstevel@tonic-gate
24657c478bd9Sstevel@tonic-gate if (cm_entry->x_waitdis == TRUE) {
24667c478bd9Sstevel@tonic-gate clock_t timout;
24677c478bd9Sstevel@tonic-gate
24687c478bd9Sstevel@tonic-gate RPCLOG(8, "connmgr_dis_and_wait waiting for "
24697c478bd9Sstevel@tonic-gate "T_DISCON_REQ's ACK for connection %p\n",
24707c478bd9Sstevel@tonic-gate (void *)cm_entry);
24717c478bd9Sstevel@tonic-gate
2472d3d50737SRafael Vanoni timout = clnt_cots_min_conntout * drv_usectohz(1000000);
24737c478bd9Sstevel@tonic-gate
24747c478bd9Sstevel@tonic-gate /*
24757c478bd9Sstevel@tonic-gate * The TPI spec says that the T_DISCON_REQ
24767c478bd9Sstevel@tonic-gate * will get acknowledged, but in practice
24777c478bd9Sstevel@tonic-gate * the ACK may never get sent. So don't
24787c478bd9Sstevel@tonic-gate * block forever.
24797c478bd9Sstevel@tonic-gate */
2480d3d50737SRafael Vanoni (void) cv_reltimedwait(&cm_entry->x_dis_cv,
2481d3d50737SRafael Vanoni &connmgr_lock, timout, TR_CLOCK_TICK);
24827c478bd9Sstevel@tonic-gate }
24837c478bd9Sstevel@tonic-gate /*
24847c478bd9Sstevel@tonic-gate * If we got the ACK, break. If we didn't,
24857c478bd9Sstevel@tonic-gate * then send another T_DISCON_REQ.
24867c478bd9Sstevel@tonic-gate */
24877c478bd9Sstevel@tonic-gate if (cm_entry->x_waitdis == FALSE) {
24887c478bd9Sstevel@tonic-gate break;
24897c478bd9Sstevel@tonic-gate } else {
24907c478bd9Sstevel@tonic-gate RPCLOG(8, "connmgr_dis_and_wait: did"
24917c478bd9Sstevel@tonic-gate "not get T_DISCON_REQ's ACK for "
24927c478bd9Sstevel@tonic-gate "connection %p\n", (void *)cm_entry);
24937c478bd9Sstevel@tonic-gate cm_entry->x_needdis = TRUE;
24947c478bd9Sstevel@tonic-gate }
24957c478bd9Sstevel@tonic-gate }
24967c478bd9Sstevel@tonic-gate }
24977c478bd9Sstevel@tonic-gate
24987c478bd9Sstevel@tonic-gate static void
connmgr_cancelconn(struct cm_xprt * cm_entry)24997c478bd9Sstevel@tonic-gate connmgr_cancelconn(struct cm_xprt *cm_entry)
25007c478bd9Sstevel@tonic-gate {
25017c478bd9Sstevel@tonic-gate /*
25027c478bd9Sstevel@tonic-gate * Mark the connection table entry as dead; the next thread that
25037c478bd9Sstevel@tonic-gate * goes through connmgr_release() will notice this and deal with it.
25047c478bd9Sstevel@tonic-gate */
25057c478bd9Sstevel@tonic-gate mutex_enter(&connmgr_lock);
25067c478bd9Sstevel@tonic-gate cm_entry->x_dead = TRUE;
25077c478bd9Sstevel@tonic-gate
25087c478bd9Sstevel@tonic-gate /*
25097c478bd9Sstevel@tonic-gate * Notify any threads waiting for the connection that it isn't
25107c478bd9Sstevel@tonic-gate * going to happen.
25117c478bd9Sstevel@tonic-gate */
25127c478bd9Sstevel@tonic-gate cm_entry->x_thread = FALSE;
25137c478bd9Sstevel@tonic-gate cv_broadcast(&cm_entry->x_conn_cv);
25147c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
25157c478bd9Sstevel@tonic-gate
25167c478bd9Sstevel@tonic-gate connmgr_release(cm_entry);
25177c478bd9Sstevel@tonic-gate }
25187c478bd9Sstevel@tonic-gate
25197c478bd9Sstevel@tonic-gate static void
connmgr_close(struct cm_xprt * cm_entry)25207c478bd9Sstevel@tonic-gate connmgr_close(struct cm_xprt *cm_entry)
25217c478bd9Sstevel@tonic-gate {
25227c478bd9Sstevel@tonic-gate mutex_enter(&cm_entry->x_lock);
25237c478bd9Sstevel@tonic-gate while (cm_entry->x_ref != 0) {
25247c478bd9Sstevel@tonic-gate /*
25257c478bd9Sstevel@tonic-gate * Must be a noninterruptible wait.
25267c478bd9Sstevel@tonic-gate */
25277c478bd9Sstevel@tonic-gate cv_wait(&cm_entry->x_cv, &cm_entry->x_lock);
25287c478bd9Sstevel@tonic-gate }
25297c478bd9Sstevel@tonic-gate
25307c478bd9Sstevel@tonic-gate if (cm_entry->x_tiptr != NULL)
25317c478bd9Sstevel@tonic-gate (void) t_kclose(cm_entry->x_tiptr, 1);
25327c478bd9Sstevel@tonic-gate
25337c478bd9Sstevel@tonic-gate mutex_exit(&cm_entry->x_lock);
25347c478bd9Sstevel@tonic-gate if (cm_entry->x_ksp != NULL) {
25357c478bd9Sstevel@tonic-gate mutex_enter(&connmgr_lock);
25367c478bd9Sstevel@tonic-gate cm_entry->x_ksp->ks_private = NULL;
25377c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
25387c478bd9Sstevel@tonic-gate
25397c478bd9Sstevel@tonic-gate /*
25407c478bd9Sstevel@tonic-gate * Must free the buffer we allocated for the
25417c478bd9Sstevel@tonic-gate * server address in the update function
25427c478bd9Sstevel@tonic-gate */
25437c478bd9Sstevel@tonic-gate if (((struct cm_kstat_xprt *)(cm_entry->x_ksp->ks_data))->
2544a1b5e537Sbmc x_server.value.str.addr.ptr != NULL)
25457c478bd9Sstevel@tonic-gate kmem_free(((struct cm_kstat_xprt *)(cm_entry->x_ksp->
2546a1b5e537Sbmc ks_data))->x_server.value.str.addr.ptr,
25477c478bd9Sstevel@tonic-gate INET6_ADDRSTRLEN);
25487c478bd9Sstevel@tonic-gate kmem_free(cm_entry->x_ksp->ks_data,
25497c478bd9Sstevel@tonic-gate cm_entry->x_ksp->ks_data_size);
25507c478bd9Sstevel@tonic-gate kstat_delete(cm_entry->x_ksp);
25517c478bd9Sstevel@tonic-gate }
25527c478bd9Sstevel@tonic-gate
25537c478bd9Sstevel@tonic-gate mutex_destroy(&cm_entry->x_lock);
25547c478bd9Sstevel@tonic-gate cv_destroy(&cm_entry->x_cv);
25557c478bd9Sstevel@tonic-gate cv_destroy(&cm_entry->x_conn_cv);
25567c478bd9Sstevel@tonic-gate cv_destroy(&cm_entry->x_dis_cv);
25577c478bd9Sstevel@tonic-gate
25587c478bd9Sstevel@tonic-gate if (cm_entry->x_server.buf != NULL)
25597c478bd9Sstevel@tonic-gate kmem_free(cm_entry->x_server.buf, cm_entry->x_server.maxlen);
25607c478bd9Sstevel@tonic-gate if (cm_entry->x_src.buf != NULL)
25617c478bd9Sstevel@tonic-gate kmem_free(cm_entry->x_src.buf, cm_entry->x_src.maxlen);
25627c478bd9Sstevel@tonic-gate kmem_free(cm_entry, sizeof (struct cm_xprt));
25637c478bd9Sstevel@tonic-gate }
25647c478bd9Sstevel@tonic-gate
25657c478bd9Sstevel@tonic-gate /*
25667c478bd9Sstevel@tonic-gate * Called by KRPC after sending the call message to release the connection
25677c478bd9Sstevel@tonic-gate * it was using.
25687c478bd9Sstevel@tonic-gate */
25697c478bd9Sstevel@tonic-gate static void
connmgr_release(struct cm_xprt * cm_entry)25707c478bd9Sstevel@tonic-gate connmgr_release(struct cm_xprt *cm_entry)
25717c478bd9Sstevel@tonic-gate {
25727c478bd9Sstevel@tonic-gate mutex_enter(&cm_entry->x_lock);
25737c478bd9Sstevel@tonic-gate cm_entry->x_ref--;
25747c478bd9Sstevel@tonic-gate if (cm_entry->x_ref == 0)
25757c478bd9Sstevel@tonic-gate cv_signal(&cm_entry->x_cv);
25767c478bd9Sstevel@tonic-gate mutex_exit(&cm_entry->x_lock);
25777c478bd9Sstevel@tonic-gate }
25787c478bd9Sstevel@tonic-gate
25797c478bd9Sstevel@tonic-gate /*
25802081ac19SDai Ngo * Set TCP receive and xmit buffer size for RPC connections.
25812081ac19SDai Ngo */
25822081ac19SDai Ngo static bool_t
connmgr_setbufsz(calllist_t * e,queue_t * wq,cred_t * cr)25832081ac19SDai Ngo connmgr_setbufsz(calllist_t *e, queue_t *wq, cred_t *cr)
25842081ac19SDai Ngo {
25852081ac19SDai Ngo int ok = FALSE;
25862081ac19SDai Ngo int val;
25872081ac19SDai Ngo
25882081ac19SDai Ngo if (rpc_default_tcp_bufsz)
25892081ac19SDai Ngo return (FALSE);
25902081ac19SDai Ngo
25912081ac19SDai Ngo /*
25922081ac19SDai Ngo * Only set new buffer size if it's larger than the system
25932081ac19SDai Ngo * default buffer size. If smaller buffer size is needed
25942081ac19SDai Ngo * then use /etc/system to set rpc_default_tcp_bufsz to 1.
25952081ac19SDai Ngo */
25962081ac19SDai Ngo ok = connmgr_getopt_int(wq, SOL_SOCKET, SO_RCVBUF, &val, e, cr);
25972081ac19SDai Ngo if ((ok == TRUE) && (val < rpc_send_bufsz)) {
25982081ac19SDai Ngo ok = connmgr_setopt_int(wq, SOL_SOCKET, SO_RCVBUF,
25992081ac19SDai Ngo rpc_send_bufsz, e, cr);
26002081ac19SDai Ngo DTRACE_PROBE2(krpc__i__connmgr_rcvbufsz,
26012081ac19SDai Ngo int, ok, calllist_t *, e);
26022081ac19SDai Ngo }
26032081ac19SDai Ngo
26042081ac19SDai Ngo ok = connmgr_getopt_int(wq, SOL_SOCKET, SO_SNDBUF, &val, e, cr);
26052081ac19SDai Ngo if ((ok == TRUE) && (val < rpc_recv_bufsz)) {
26062081ac19SDai Ngo ok = connmgr_setopt_int(wq, SOL_SOCKET, SO_SNDBUF,
26072081ac19SDai Ngo rpc_recv_bufsz, e, cr);
26082081ac19SDai Ngo DTRACE_PROBE2(krpc__i__connmgr_sndbufsz,
26092081ac19SDai Ngo int, ok, calllist_t *, e);
26102081ac19SDai Ngo }
26112081ac19SDai Ngo return (TRUE);
26122081ac19SDai Ngo }
26132081ac19SDai Ngo
26142081ac19SDai Ngo /*
26157c478bd9Sstevel@tonic-gate * Given an open stream, connect to the remote. Returns true if connected,
26167c478bd9Sstevel@tonic-gate * false otherwise.
26177c478bd9Sstevel@tonic-gate */
26187c478bd9Sstevel@tonic-gate static bool_t
connmgr_connect(struct cm_xprt * cm_entry,queue_t * wq,struct netbuf * addr,int addrfmly,calllist_t * e,int * tidu_ptr,bool_t reconnect,const struct timeval * waitp,bool_t nosignal,cred_t * cr)26197c478bd9Sstevel@tonic-gate connmgr_connect(
26207c478bd9Sstevel@tonic-gate struct cm_xprt *cm_entry,
26217c478bd9Sstevel@tonic-gate queue_t *wq,
26227c478bd9Sstevel@tonic-gate struct netbuf *addr,
26237c478bd9Sstevel@tonic-gate int addrfmly,
26247c478bd9Sstevel@tonic-gate calllist_t *e,
26257c478bd9Sstevel@tonic-gate int *tidu_ptr,
26267c478bd9Sstevel@tonic-gate bool_t reconnect,
26277c478bd9Sstevel@tonic-gate const struct timeval *waitp,
2628de8c4a14SErik Nordmark bool_t nosignal,
2629de8c4a14SErik Nordmark cred_t *cr)
26307c478bd9Sstevel@tonic-gate {
26317c478bd9Sstevel@tonic-gate mblk_t *mp;
26327c478bd9Sstevel@tonic-gate struct T_conn_req *tcr;
26337c478bd9Sstevel@tonic-gate struct T_info_ack *tinfo;
26347c478bd9Sstevel@tonic-gate int interrupted, error;
26357c478bd9Sstevel@tonic-gate int tidu_size, kstat_instance;
26367c478bd9Sstevel@tonic-gate
26377c478bd9Sstevel@tonic-gate /* if it's a reconnect, flush any lingering data messages */
26387c478bd9Sstevel@tonic-gate if (reconnect)
26397c478bd9Sstevel@tonic-gate (void) putctl1(wq, M_FLUSH, FLUSHRW);
26407c478bd9Sstevel@tonic-gate
2641de8c4a14SErik Nordmark /*
2642de8c4a14SErik Nordmark * Note: if the receiver uses SCM_UCRED/getpeerucred the pid will
2643de8c4a14SErik Nordmark * appear as -1.
2644de8c4a14SErik Nordmark */
2645de8c4a14SErik Nordmark mp = allocb_cred(sizeof (*tcr) + addr->len, cr, NOPID);
26467c478bd9Sstevel@tonic-gate if (mp == NULL) {
26477c478bd9Sstevel@tonic-gate /*
26487c478bd9Sstevel@tonic-gate * This is unfortunate, but we need to look up the stats for
26497c478bd9Sstevel@tonic-gate * this zone to increment the "memory allocation failed"
26507c478bd9Sstevel@tonic-gate * counter. curproc->p_zone is safe since we're initiating a
26517c478bd9Sstevel@tonic-gate * connection and not in some strange streams context.
26527c478bd9Sstevel@tonic-gate */
26537c478bd9Sstevel@tonic-gate struct rpcstat *rpcstat;
26547c478bd9Sstevel@tonic-gate
2655108322fbScarlsonj rpcstat = zone_getspecific(rpcstat_zone_key, rpc_zone());
26567c478bd9Sstevel@tonic-gate ASSERT(rpcstat != NULL);
26577c478bd9Sstevel@tonic-gate
26587c478bd9Sstevel@tonic-gate RPCLOG0(1, "connmgr_connect: cannot alloc mp for "
26597c478bd9Sstevel@tonic-gate "sending conn request\n");
26607c478bd9Sstevel@tonic-gate COTSRCSTAT_INCR(rpcstat->rpc_cots_client, rcnomem);
26617c478bd9Sstevel@tonic-gate e->call_status = RPC_SYSTEMERROR;
26627c478bd9Sstevel@tonic-gate e->call_reason = ENOSR;
26637c478bd9Sstevel@tonic-gate return (FALSE);
26647c478bd9Sstevel@tonic-gate }
26657c478bd9Sstevel@tonic-gate
26662081ac19SDai Ngo /* Set TCP buffer size for RPC connections if needed */
26672081ac19SDai Ngo if (addrfmly == AF_INET || addrfmly == AF_INET6)
26682081ac19SDai Ngo (void) connmgr_setbufsz(e, wq, cr);
26692081ac19SDai Ngo
26707c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO;
26717c478bd9Sstevel@tonic-gate tcr = (struct T_conn_req *)mp->b_rptr;
26727c478bd9Sstevel@tonic-gate bzero(tcr, sizeof (*tcr));
26737c478bd9Sstevel@tonic-gate tcr->PRIM_type = T_CONN_REQ;
26747c478bd9Sstevel@tonic-gate tcr->DEST_length = addr->len;
26757c478bd9Sstevel@tonic-gate tcr->DEST_offset = sizeof (struct T_conn_req);
26767c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (*tcr);
26777c478bd9Sstevel@tonic-gate
26787c478bd9Sstevel@tonic-gate bcopy(addr->buf, mp->b_wptr, tcr->DEST_length);
26797c478bd9Sstevel@tonic-gate mp->b_wptr += tcr->DEST_length;
26807c478bd9Sstevel@tonic-gate
26817c478bd9Sstevel@tonic-gate RPCLOG(8, "connmgr_connect: sending conn request on queue "
26827c478bd9Sstevel@tonic-gate "%p", (void *)wq);
26837c478bd9Sstevel@tonic-gate RPCLOG(8, " call %p\n", (void *)wq);
26847c478bd9Sstevel@tonic-gate /*
26857c478bd9Sstevel@tonic-gate * We use the entry in the handle that is normally used for
26867c478bd9Sstevel@tonic-gate * waiting for RPC replies to wait for the connection accept.
26877c478bd9Sstevel@tonic-gate */
2688125a8fd9SSiddheshwar Mahesh if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) {
2689125a8fd9SSiddheshwar Mahesh DTRACE_PROBE(krpc__e__connmgr__connect__cantsend);
2690125a8fd9SSiddheshwar Mahesh freemsg(mp);
2691125a8fd9SSiddheshwar Mahesh return (FALSE);
2692125a8fd9SSiddheshwar Mahesh }
26937c478bd9Sstevel@tonic-gate
26947c478bd9Sstevel@tonic-gate mutex_enter(&clnt_pending_lock);
26957c478bd9Sstevel@tonic-gate
26967c478bd9Sstevel@tonic-gate /*
26977c478bd9Sstevel@tonic-gate * We wait for the transport connection to be made, or an
26987c478bd9Sstevel@tonic-gate * indication that it could not be made.
26997c478bd9Sstevel@tonic-gate */
27007c478bd9Sstevel@tonic-gate interrupted = 0;
27017c478bd9Sstevel@tonic-gate
27027c478bd9Sstevel@tonic-gate /*
27037c478bd9Sstevel@tonic-gate * waitforack should have been called with T_OK_ACK, but the
27047c478bd9Sstevel@tonic-gate * present implementation needs to be passed T_INFO_ACK to
27057c478bd9Sstevel@tonic-gate * work correctly.
27067c478bd9Sstevel@tonic-gate */
27077c478bd9Sstevel@tonic-gate error = waitforack(e, T_INFO_ACK, waitp, nosignal);
27087c478bd9Sstevel@tonic-gate if (error == EINTR)
27097c478bd9Sstevel@tonic-gate interrupted = 1;
27107c478bd9Sstevel@tonic-gate if (zone_status_get(curproc->p_zone) >= ZONE_IS_EMPTY) {
27117c478bd9Sstevel@tonic-gate /*
27127c478bd9Sstevel@tonic-gate * No time to lose; we essentially have been signaled to
27137c478bd9Sstevel@tonic-gate * quit.
27147c478bd9Sstevel@tonic-gate */
27157c478bd9Sstevel@tonic-gate interrupted = 1;
27167c478bd9Sstevel@tonic-gate }
27177c478bd9Sstevel@tonic-gate #ifdef RPCDEBUG
27187c478bd9Sstevel@tonic-gate if (error == ETIME)
27197c478bd9Sstevel@tonic-gate RPCLOG0(8, "connmgr_connect: giving up "
27207c478bd9Sstevel@tonic-gate "on connection attempt; "
27217c478bd9Sstevel@tonic-gate "clnt_dispatch notifyconn "
27227c478bd9Sstevel@tonic-gate "diagnostic 'no one waiting for "
27237c478bd9Sstevel@tonic-gate "connection' should not be "
27247c478bd9Sstevel@tonic-gate "unexpected\n");
27257c478bd9Sstevel@tonic-gate #endif
27267c478bd9Sstevel@tonic-gate if (e->call_prev)
27277c478bd9Sstevel@tonic-gate e->call_prev->call_next = e->call_next;
27287c478bd9Sstevel@tonic-gate else
27297c478bd9Sstevel@tonic-gate clnt_pending = e->call_next;
27307c478bd9Sstevel@tonic-gate if (e->call_next)
27317c478bd9Sstevel@tonic-gate e->call_next->call_prev = e->call_prev;
27327c478bd9Sstevel@tonic-gate mutex_exit(&clnt_pending_lock);
27337c478bd9Sstevel@tonic-gate
27347c478bd9Sstevel@tonic-gate if (e->call_status != RPC_SUCCESS || error != 0) {
27357c478bd9Sstevel@tonic-gate if (interrupted)
27367c478bd9Sstevel@tonic-gate e->call_status = RPC_INTR;
27377c478bd9Sstevel@tonic-gate else if (error == ETIME)
27387c478bd9Sstevel@tonic-gate e->call_status = RPC_TIMEDOUT;
27398c3630f0SGerald Thornbrugh else if (error == EPROTO) {
27407c478bd9Sstevel@tonic-gate e->call_status = RPC_SYSTEMERROR;
27418c3630f0SGerald Thornbrugh e->call_reason = EPROTO;
27428c3630f0SGerald Thornbrugh }
27437c478bd9Sstevel@tonic-gate
27447c478bd9Sstevel@tonic-gate RPCLOG(8, "connmgr_connect: can't connect, status: "
27457c478bd9Sstevel@tonic-gate "%s\n", clnt_sperrno(e->call_status));
27467c478bd9Sstevel@tonic-gate
27477c478bd9Sstevel@tonic-gate if (e->call_reply) {
27487c478bd9Sstevel@tonic-gate freemsg(e->call_reply);
27497c478bd9Sstevel@tonic-gate e->call_reply = NULL;
27507c478bd9Sstevel@tonic-gate }
27517c478bd9Sstevel@tonic-gate
27527c478bd9Sstevel@tonic-gate return (FALSE);
27537c478bd9Sstevel@tonic-gate }
27547c478bd9Sstevel@tonic-gate /*
27557c478bd9Sstevel@tonic-gate * The result of the "connection accept" is a T_info_ack
27567c478bd9Sstevel@tonic-gate * in the call_reply field.
27577c478bd9Sstevel@tonic-gate */
27587c478bd9Sstevel@tonic-gate ASSERT(e->call_reply != NULL);
27597c478bd9Sstevel@tonic-gate mp = e->call_reply;
27607c478bd9Sstevel@tonic-gate e->call_reply = NULL;
27617c478bd9Sstevel@tonic-gate tinfo = (struct T_info_ack *)mp->b_rptr;
27627c478bd9Sstevel@tonic-gate
27637c478bd9Sstevel@tonic-gate tidu_size = tinfo->TIDU_size;
27647c478bd9Sstevel@tonic-gate tidu_size -= (tidu_size % BYTES_PER_XDR_UNIT);
27657c478bd9Sstevel@tonic-gate if (tidu_size > COTS_DEFAULT_ALLOCSIZE || (tidu_size <= 0))
27667c478bd9Sstevel@tonic-gate tidu_size = COTS_DEFAULT_ALLOCSIZE;
27677c478bd9Sstevel@tonic-gate *tidu_ptr = tidu_size;
27687c478bd9Sstevel@tonic-gate
27697c478bd9Sstevel@tonic-gate freemsg(mp);
27707c478bd9Sstevel@tonic-gate
27717c478bd9Sstevel@tonic-gate /*
27727c478bd9Sstevel@tonic-gate * Set up the pertinent options. NODELAY is so the transport doesn't
27737c478bd9Sstevel@tonic-gate * buffer up RPC messages on either end. This may not be valid for
27747c478bd9Sstevel@tonic-gate * all transports. Failure to set this option is not cause to
27757c478bd9Sstevel@tonic-gate * bail out so we return success anyway. Note that lack of NODELAY
27767c478bd9Sstevel@tonic-gate * or some other way to flush the message on both ends will cause
27777c478bd9Sstevel@tonic-gate * lots of retries and terrible performance.
27787c478bd9Sstevel@tonic-gate */
27797c478bd9Sstevel@tonic-gate if (addrfmly == AF_INET || addrfmly == AF_INET6) {
2780de8c4a14SErik Nordmark (void) connmgr_setopt(wq, IPPROTO_TCP, TCP_NODELAY, e, cr);
27817c478bd9Sstevel@tonic-gate if (e->call_status == RPC_XPRTFAILED)
27827c478bd9Sstevel@tonic-gate return (FALSE);
27837c478bd9Sstevel@tonic-gate }
27847c478bd9Sstevel@tonic-gate
27857c478bd9Sstevel@tonic-gate /*
27867c478bd9Sstevel@tonic-gate * Since we have a connection, we now need to figure out if
27877c478bd9Sstevel@tonic-gate * we need to create a kstat. If x_ksp is not NULL then we
27887c478bd9Sstevel@tonic-gate * are reusing a connection and so we do not need to create
27897c478bd9Sstevel@tonic-gate * another kstat -- lets just return.
27907c478bd9Sstevel@tonic-gate */
27917c478bd9Sstevel@tonic-gate if (cm_entry->x_ksp != NULL)
27927c478bd9Sstevel@tonic-gate return (TRUE);
27937c478bd9Sstevel@tonic-gate
27947c478bd9Sstevel@tonic-gate /*
27957c478bd9Sstevel@tonic-gate * We need to increment rpc_kstat_instance atomically to prevent
27967c478bd9Sstevel@tonic-gate * two kstats being created with the same instance.
27977c478bd9Sstevel@tonic-gate */
2798*1a5e258fSJosef 'Jeff' Sipek kstat_instance = atomic_inc_32_nv((uint32_t *)&rpc_kstat_instance);
27997c478bd9Sstevel@tonic-gate
28007c478bd9Sstevel@tonic-gate if ((cm_entry->x_ksp = kstat_create_zone("unix", kstat_instance,
28017c478bd9Sstevel@tonic-gate "rpc_cots_connections", "rpc", KSTAT_TYPE_NAMED,
28027c478bd9Sstevel@tonic-gate (uint_t)(sizeof (cm_kstat_xprt_t) / sizeof (kstat_named_t)),
28037c478bd9Sstevel@tonic-gate KSTAT_FLAG_VIRTUAL, cm_entry->x_zoneid)) == NULL) {
28047c478bd9Sstevel@tonic-gate return (TRUE);
28057c478bd9Sstevel@tonic-gate }
28067c478bd9Sstevel@tonic-gate
28077c478bd9Sstevel@tonic-gate cm_entry->x_ksp->ks_lock = &connmgr_lock;
28087c478bd9Sstevel@tonic-gate cm_entry->x_ksp->ks_private = cm_entry;
28097c478bd9Sstevel@tonic-gate cm_entry->x_ksp->ks_data_size = ((INET6_ADDRSTRLEN * sizeof (char))
28107c478bd9Sstevel@tonic-gate + sizeof (cm_kstat_template));
28117c478bd9Sstevel@tonic-gate cm_entry->x_ksp->ks_data = kmem_alloc(cm_entry->x_ksp->ks_data_size,
28127c478bd9Sstevel@tonic-gate KM_SLEEP);
28137c478bd9Sstevel@tonic-gate bcopy(&cm_kstat_template, cm_entry->x_ksp->ks_data,
28147c478bd9Sstevel@tonic-gate cm_entry->x_ksp->ks_data_size);
28157c478bd9Sstevel@tonic-gate ((struct cm_kstat_xprt *)(cm_entry->x_ksp->ks_data))->
2816a1b5e537Sbmc x_server.value.str.addr.ptr =
28177c478bd9Sstevel@tonic-gate kmem_alloc(INET6_ADDRSTRLEN, KM_SLEEP);
28187c478bd9Sstevel@tonic-gate
28197c478bd9Sstevel@tonic-gate cm_entry->x_ksp->ks_update = conn_kstat_update;
28207c478bd9Sstevel@tonic-gate kstat_install(cm_entry->x_ksp);
28217c478bd9Sstevel@tonic-gate return (TRUE);
28227c478bd9Sstevel@tonic-gate }
28237c478bd9Sstevel@tonic-gate
28247c478bd9Sstevel@tonic-gate /*
28252081ac19SDai Ngo * Verify that the specified offset falls within the mblk and
28262081ac19SDai Ngo * that the resulting pointer is aligned.
28272081ac19SDai Ngo * Returns NULL if not.
28282081ac19SDai Ngo *
28292081ac19SDai Ngo * code from fs/sockfs/socksubr.c
28302081ac19SDai Ngo */
28312081ac19SDai Ngo static void *
connmgr_opt_getoff(mblk_t * mp,t_uscalar_t offset,t_uscalar_t length,uint_t align_size)28322081ac19SDai Ngo connmgr_opt_getoff(mblk_t *mp, t_uscalar_t offset,
28332081ac19SDai Ngo t_uscalar_t length, uint_t align_size)
28342081ac19SDai Ngo {
28352081ac19SDai Ngo uintptr_t ptr1, ptr2;
28362081ac19SDai Ngo
28372081ac19SDai Ngo ASSERT(mp && mp->b_wptr >= mp->b_rptr);
28382081ac19SDai Ngo ptr1 = (uintptr_t)mp->b_rptr + offset;
28392081ac19SDai Ngo ptr2 = (uintptr_t)ptr1 + length;
28402081ac19SDai Ngo if (ptr1 < (uintptr_t)mp->b_rptr || ptr2 > (uintptr_t)mp->b_wptr) {
28412081ac19SDai Ngo return (NULL);
28422081ac19SDai Ngo }
28432081ac19SDai Ngo if ((ptr1 & (align_size - 1)) != 0) {
28442081ac19SDai Ngo return (NULL);
28452081ac19SDai Ngo }
28462081ac19SDai Ngo return ((void *)ptr1);
28472081ac19SDai Ngo }
28482081ac19SDai Ngo
28492081ac19SDai Ngo static bool_t
connmgr_getopt_int(queue_t * wq,int level,int name,int * val,calllist_t * e,cred_t * cr)28502081ac19SDai Ngo connmgr_getopt_int(queue_t *wq, int level, int name, int *val,
28512081ac19SDai Ngo calllist_t *e, cred_t *cr)
28522081ac19SDai Ngo {
28532081ac19SDai Ngo mblk_t *mp;
28542081ac19SDai Ngo struct opthdr *opt, *opt_res;
28552081ac19SDai Ngo struct T_optmgmt_req *tor;
28562081ac19SDai Ngo struct T_optmgmt_ack *opt_ack;
28572081ac19SDai Ngo struct timeval waitp;
28582081ac19SDai Ngo int error;
28592081ac19SDai Ngo
28602081ac19SDai Ngo mp = allocb_cred(sizeof (struct T_optmgmt_req) +
28612081ac19SDai Ngo sizeof (struct opthdr) + sizeof (int), cr, NOPID);
28622081ac19SDai Ngo if (mp == NULL)
28632081ac19SDai Ngo return (FALSE);
28642081ac19SDai Ngo
28652081ac19SDai Ngo mp->b_datap->db_type = M_PROTO;
28662081ac19SDai Ngo tor = (struct T_optmgmt_req *)(mp->b_rptr);
28672081ac19SDai Ngo tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
28682081ac19SDai Ngo tor->MGMT_flags = T_CURRENT;
28692081ac19SDai Ngo tor->OPT_length = sizeof (struct opthdr) + sizeof (int);
28702081ac19SDai Ngo tor->OPT_offset = sizeof (struct T_optmgmt_req);
28712081ac19SDai Ngo
28722081ac19SDai Ngo opt = (struct opthdr *)(mp->b_rptr + sizeof (struct T_optmgmt_req));
28732081ac19SDai Ngo opt->level = level;
28742081ac19SDai Ngo opt->name = name;
28752081ac19SDai Ngo opt->len = sizeof (int);
28762081ac19SDai Ngo mp->b_wptr += sizeof (struct T_optmgmt_req) + sizeof (struct opthdr) +
28772081ac19SDai Ngo sizeof (int);
28782081ac19SDai Ngo
28792081ac19SDai Ngo /*
28802081ac19SDai Ngo * We will use this connection regardless
28812081ac19SDai Ngo * of whether or not the option is readable.
28822081ac19SDai Ngo */
28832081ac19SDai Ngo if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) {
28842081ac19SDai Ngo DTRACE_PROBE(krpc__e__connmgr__getopt__cantsend);
28852081ac19SDai Ngo freemsg(mp);
28862081ac19SDai Ngo return (FALSE);
28872081ac19SDai Ngo }
28882081ac19SDai Ngo
28892081ac19SDai Ngo mutex_enter(&clnt_pending_lock);
28902081ac19SDai Ngo
28912081ac19SDai Ngo waitp.tv_sec = clnt_cots_min_conntout;
28922081ac19SDai Ngo waitp.tv_usec = 0;
28932081ac19SDai Ngo error = waitforack(e, T_OPTMGMT_ACK, &waitp, 1);
28942081ac19SDai Ngo
28952081ac19SDai Ngo if (e->call_prev)
28962081ac19SDai Ngo e->call_prev->call_next = e->call_next;
28972081ac19SDai Ngo else
28982081ac19SDai Ngo clnt_pending = e->call_next;
28992081ac19SDai Ngo if (e->call_next)
29002081ac19SDai Ngo e->call_next->call_prev = e->call_prev;
29012081ac19SDai Ngo mutex_exit(&clnt_pending_lock);
29022081ac19SDai Ngo
29032081ac19SDai Ngo /* get reply message */
29042081ac19SDai Ngo mp = e->call_reply;
29052081ac19SDai Ngo e->call_reply = NULL;
29062081ac19SDai Ngo
29072081ac19SDai Ngo if ((!mp) || (e->call_status != RPC_SUCCESS) || (error != 0)) {
29082081ac19SDai Ngo
29092081ac19SDai Ngo DTRACE_PROBE4(krpc__e__connmgr_getopt, int, name,
29102081ac19SDai Ngo int, e->call_status, int, error, mblk_t *, mp);
29112081ac19SDai Ngo
29122081ac19SDai Ngo if (mp)
29132081ac19SDai Ngo freemsg(mp);
29142081ac19SDai Ngo return (FALSE);
29152081ac19SDai Ngo }
29162081ac19SDai Ngo
29172081ac19SDai Ngo opt_ack = (struct T_optmgmt_ack *)mp->b_rptr;
29182081ac19SDai Ngo opt_res = (struct opthdr *)connmgr_opt_getoff(mp, opt_ack->OPT_offset,
29192081ac19SDai Ngo opt_ack->OPT_length, __TPI_ALIGN_SIZE);
29202081ac19SDai Ngo
29212081ac19SDai Ngo if (!opt_res) {
29222081ac19SDai Ngo DTRACE_PROBE4(krpc__e__connmgr_optres, mblk_t *, mp, int, name,
29232081ac19SDai Ngo int, opt_ack->OPT_offset, int, opt_ack->OPT_length);
29242081ac19SDai Ngo freemsg(mp);
29252081ac19SDai Ngo return (FALSE);
29262081ac19SDai Ngo }
29272081ac19SDai Ngo *val = *(int *)&opt_res[1];
29282081ac19SDai Ngo
29292081ac19SDai Ngo DTRACE_PROBE2(connmgr_getopt__ok, int, name, int, *val);
29302081ac19SDai Ngo
29312081ac19SDai Ngo freemsg(mp);
29322081ac19SDai Ngo return (TRUE);
29332081ac19SDai Ngo }
29342081ac19SDai Ngo
29352081ac19SDai Ngo /*
29367c478bd9Sstevel@tonic-gate * Called by connmgr_connect to set an option on the new stream.
29377c478bd9Sstevel@tonic-gate */
29387c478bd9Sstevel@tonic-gate static bool_t
connmgr_setopt_int(queue_t * wq,int level,int name,int val,calllist_t * e,cred_t * cr)29392081ac19SDai Ngo connmgr_setopt_int(queue_t *wq, int level, int name, int val,
29402081ac19SDai Ngo calllist_t *e, cred_t *cr)
29417c478bd9Sstevel@tonic-gate {
29427c478bd9Sstevel@tonic-gate mblk_t *mp;
29437c478bd9Sstevel@tonic-gate struct opthdr *opt;
29447c478bd9Sstevel@tonic-gate struct T_optmgmt_req *tor;
29457c478bd9Sstevel@tonic-gate struct timeval waitp;
29467c478bd9Sstevel@tonic-gate int error;
29477c478bd9Sstevel@tonic-gate
2948de8c4a14SErik Nordmark mp = allocb_cred(sizeof (struct T_optmgmt_req) +
2949de8c4a14SErik Nordmark sizeof (struct opthdr) + sizeof (int), cr, NOPID);
29507c478bd9Sstevel@tonic-gate if (mp == NULL) {
29517c478bd9Sstevel@tonic-gate RPCLOG0(1, "connmgr_setopt: cannot alloc mp for option "
29527c478bd9Sstevel@tonic-gate "request\n");
29537c478bd9Sstevel@tonic-gate return (FALSE);
29547c478bd9Sstevel@tonic-gate }
29557c478bd9Sstevel@tonic-gate
29567c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO;
29577c478bd9Sstevel@tonic-gate tor = (struct T_optmgmt_req *)(mp->b_rptr);
29587c478bd9Sstevel@tonic-gate tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
29597c478bd9Sstevel@tonic-gate tor->MGMT_flags = T_NEGOTIATE;
29607c478bd9Sstevel@tonic-gate tor->OPT_length = sizeof (struct opthdr) + sizeof (int);
29617c478bd9Sstevel@tonic-gate tor->OPT_offset = sizeof (struct T_optmgmt_req);
29627c478bd9Sstevel@tonic-gate
29637c478bd9Sstevel@tonic-gate opt = (struct opthdr *)(mp->b_rptr + sizeof (struct T_optmgmt_req));
29647c478bd9Sstevel@tonic-gate opt->level = level;
29657c478bd9Sstevel@tonic-gate opt->name = name;
29667c478bd9Sstevel@tonic-gate opt->len = sizeof (int);
29672081ac19SDai Ngo *(int *)((char *)opt + sizeof (*opt)) = val;
29687c478bd9Sstevel@tonic-gate mp->b_wptr += sizeof (struct T_optmgmt_req) + sizeof (struct opthdr) +
29697c478bd9Sstevel@tonic-gate sizeof (int);
29707c478bd9Sstevel@tonic-gate
29717c478bd9Sstevel@tonic-gate /*
29727c478bd9Sstevel@tonic-gate * We will use this connection regardless
29737c478bd9Sstevel@tonic-gate * of whether or not the option is settable.
29747c478bd9Sstevel@tonic-gate */
2975125a8fd9SSiddheshwar Mahesh if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) {
2976125a8fd9SSiddheshwar Mahesh DTRACE_PROBE(krpc__e__connmgr__setopt__cantsend);
2977125a8fd9SSiddheshwar Mahesh freemsg(mp);
2978125a8fd9SSiddheshwar Mahesh return (FALSE);
2979125a8fd9SSiddheshwar Mahesh }
2980125a8fd9SSiddheshwar Mahesh
29817c478bd9Sstevel@tonic-gate mutex_enter(&clnt_pending_lock);
29827c478bd9Sstevel@tonic-gate
29837c478bd9Sstevel@tonic-gate waitp.tv_sec = clnt_cots_min_conntout;
29847c478bd9Sstevel@tonic-gate waitp.tv_usec = 0;
29857c478bd9Sstevel@tonic-gate error = waitforack(e, T_OPTMGMT_ACK, &waitp, 1);
29867c478bd9Sstevel@tonic-gate
29877c478bd9Sstevel@tonic-gate if (e->call_prev)
29887c478bd9Sstevel@tonic-gate e->call_prev->call_next = e->call_next;
29897c478bd9Sstevel@tonic-gate else
29907c478bd9Sstevel@tonic-gate clnt_pending = e->call_next;
29917c478bd9Sstevel@tonic-gate if (e->call_next)
29927c478bd9Sstevel@tonic-gate e->call_next->call_prev = e->call_prev;
29937c478bd9Sstevel@tonic-gate mutex_exit(&clnt_pending_lock);
29947c478bd9Sstevel@tonic-gate
29957c478bd9Sstevel@tonic-gate if (e->call_reply != NULL) {
29967c478bd9Sstevel@tonic-gate freemsg(e->call_reply);
29977c478bd9Sstevel@tonic-gate e->call_reply = NULL;
29987c478bd9Sstevel@tonic-gate }
29997c478bd9Sstevel@tonic-gate
30007c478bd9Sstevel@tonic-gate if (e->call_status != RPC_SUCCESS || error != 0) {
30017c478bd9Sstevel@tonic-gate RPCLOG(1, "connmgr_setopt: can't set option: %d\n", name);
30027c478bd9Sstevel@tonic-gate return (FALSE);
30037c478bd9Sstevel@tonic-gate }
30047c478bd9Sstevel@tonic-gate RPCLOG(8, "connmgr_setopt: successfully set option: %d\n", name);
30057c478bd9Sstevel@tonic-gate return (TRUE);
30067c478bd9Sstevel@tonic-gate }
30077c478bd9Sstevel@tonic-gate
30082081ac19SDai Ngo static bool_t
connmgr_setopt(queue_t * wq,int level,int name,calllist_t * e,cred_t * cr)30092081ac19SDai Ngo connmgr_setopt(queue_t *wq, int level, int name, calllist_t *e, cred_t *cr)
30102081ac19SDai Ngo {
30112081ac19SDai Ngo return (connmgr_setopt_int(wq, level, name, 1, e, cr));
30122081ac19SDai Ngo }
30132081ac19SDai Ngo
30147c478bd9Sstevel@tonic-gate #ifdef DEBUG
30157c478bd9Sstevel@tonic-gate
30167c478bd9Sstevel@tonic-gate /*
30177c478bd9Sstevel@tonic-gate * This is a knob to let us force code coverage in allocation failure
30187c478bd9Sstevel@tonic-gate * case.
30197c478bd9Sstevel@tonic-gate */
30207c478bd9Sstevel@tonic-gate static int connmgr_failsnd;
30217c478bd9Sstevel@tonic-gate #define CONN_SND_ALLOC(Size, Pri) \
30227c478bd9Sstevel@tonic-gate ((connmgr_failsnd-- > 0) ? NULL : allocb(Size, Pri))
30237c478bd9Sstevel@tonic-gate
30247c478bd9Sstevel@tonic-gate #else
30257c478bd9Sstevel@tonic-gate
30267c478bd9Sstevel@tonic-gate #define CONN_SND_ALLOC(Size, Pri) allocb(Size, Pri)
30277c478bd9Sstevel@tonic-gate
30287c478bd9Sstevel@tonic-gate #endif
30297c478bd9Sstevel@tonic-gate
30307c478bd9Sstevel@tonic-gate /*
30317c478bd9Sstevel@tonic-gate * Sends an orderly release on the specified queue.
30327c478bd9Sstevel@tonic-gate * Entered with connmgr_lock. Exited without connmgr_lock
30337c478bd9Sstevel@tonic-gate */
30347c478bd9Sstevel@tonic-gate static void
connmgr_sndrel(struct cm_xprt * cm_entry)30357c478bd9Sstevel@tonic-gate connmgr_sndrel(struct cm_xprt *cm_entry)
30367c478bd9Sstevel@tonic-gate {
30377c478bd9Sstevel@tonic-gate struct T_ordrel_req *torr;
30387c478bd9Sstevel@tonic-gate mblk_t *mp;
30397c478bd9Sstevel@tonic-gate queue_t *q = cm_entry->x_wq;
30407c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&connmgr_lock));
30417c478bd9Sstevel@tonic-gate mp = CONN_SND_ALLOC(sizeof (struct T_ordrel_req), BPRI_LO);
30427c478bd9Sstevel@tonic-gate if (mp == NULL) {
30437c478bd9Sstevel@tonic-gate cm_entry->x_needrel = TRUE;
30447c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
30457c478bd9Sstevel@tonic-gate RPCLOG(1, "connmgr_sndrel: cannot alloc mp for sending ordrel "
30467c478bd9Sstevel@tonic-gate "to queue %p\n", (void *)q);
30477c478bd9Sstevel@tonic-gate return;
30487c478bd9Sstevel@tonic-gate }
30497c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
30507c478bd9Sstevel@tonic-gate
30517c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO;
30527c478bd9Sstevel@tonic-gate torr = (struct T_ordrel_req *)(mp->b_rptr);
30537c478bd9Sstevel@tonic-gate torr->PRIM_type = T_ORDREL_REQ;
30547c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (struct T_ordrel_req);
30557c478bd9Sstevel@tonic-gate
30567c478bd9Sstevel@tonic-gate RPCLOG(8, "connmgr_sndrel: sending ordrel to queue %p\n", (void *)q);
30577c478bd9Sstevel@tonic-gate put(q, mp);
30587c478bd9Sstevel@tonic-gate }
30597c478bd9Sstevel@tonic-gate
30607c478bd9Sstevel@tonic-gate /*
30617c478bd9Sstevel@tonic-gate * Sends an disconnect on the specified queue.
30627c478bd9Sstevel@tonic-gate * Entered with connmgr_lock. Exited without connmgr_lock
30637c478bd9Sstevel@tonic-gate */
30647c478bd9Sstevel@tonic-gate static void
connmgr_snddis(struct cm_xprt * cm_entry)30657c478bd9Sstevel@tonic-gate connmgr_snddis(struct cm_xprt *cm_entry)
30667c478bd9Sstevel@tonic-gate {
30677c478bd9Sstevel@tonic-gate struct T_discon_req *tdis;
30687c478bd9Sstevel@tonic-gate mblk_t *mp;
30697c478bd9Sstevel@tonic-gate queue_t *q = cm_entry->x_wq;
30707c478bd9Sstevel@tonic-gate
30717c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&connmgr_lock));
30727c478bd9Sstevel@tonic-gate mp = CONN_SND_ALLOC(sizeof (*tdis), BPRI_LO);
30737c478bd9Sstevel@tonic-gate if (mp == NULL) {
30747c478bd9Sstevel@tonic-gate cm_entry->x_needdis = TRUE;
30757c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
30767c478bd9Sstevel@tonic-gate RPCLOG(1, "connmgr_snddis: cannot alloc mp for sending discon "
30777c478bd9Sstevel@tonic-gate "to queue %p\n", (void *)q);
30787c478bd9Sstevel@tonic-gate return;
30797c478bd9Sstevel@tonic-gate }
30807c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
30817c478bd9Sstevel@tonic-gate
30827c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO;
30837c478bd9Sstevel@tonic-gate tdis = (struct T_discon_req *)mp->b_rptr;
30847c478bd9Sstevel@tonic-gate tdis->PRIM_type = T_DISCON_REQ;
30857c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (*tdis);
30867c478bd9Sstevel@tonic-gate
30877c478bd9Sstevel@tonic-gate RPCLOG(8, "connmgr_snddis: sending discon to queue %p\n", (void *)q);
30887c478bd9Sstevel@tonic-gate put(q, mp);
30897c478bd9Sstevel@tonic-gate }
30907c478bd9Sstevel@tonic-gate
30917c478bd9Sstevel@tonic-gate /*
30927c478bd9Sstevel@tonic-gate * Sets up the entry for receiving replies, and calls rpcmod's write put proc
30937c478bd9Sstevel@tonic-gate * (through put) to send the call.
30947c478bd9Sstevel@tonic-gate */
3095125a8fd9SSiddheshwar Mahesh static int
clnt_dispatch_send(queue_t * q,mblk_t * mp,calllist_t * e,uint_t xid,uint_t queue_flag)30967c478bd9Sstevel@tonic-gate clnt_dispatch_send(queue_t *q, mblk_t *mp, calllist_t *e, uint_t xid,
30977c478bd9Sstevel@tonic-gate uint_t queue_flag)
30987c478bd9Sstevel@tonic-gate {
30997c478bd9Sstevel@tonic-gate ASSERT(e != NULL);
31007c478bd9Sstevel@tonic-gate
31017c478bd9Sstevel@tonic-gate e->call_status = RPC_TIMEDOUT; /* optimistic, eh? */
31027c478bd9Sstevel@tonic-gate e->call_reason = 0;
31037c478bd9Sstevel@tonic-gate e->call_wq = q;
31047c478bd9Sstevel@tonic-gate e->call_xid = xid;
31057c478bd9Sstevel@tonic-gate e->call_notified = FALSE;
31067c478bd9Sstevel@tonic-gate
3107125a8fd9SSiddheshwar Mahesh if (!canput(q)) {
3108125a8fd9SSiddheshwar Mahesh e->call_status = RPC_CANTSEND;
3109e280ed37SDai Ngo e->call_reason = ENOBUFS;
3110125a8fd9SSiddheshwar Mahesh return (RPC_CANTSEND);
3111125a8fd9SSiddheshwar Mahesh }
3112125a8fd9SSiddheshwar Mahesh
31137c478bd9Sstevel@tonic-gate /*
31147c478bd9Sstevel@tonic-gate * If queue_flag is set then the calllist_t is already on the hash
31157c478bd9Sstevel@tonic-gate * queue. In this case just send the message and return.
31167c478bd9Sstevel@tonic-gate */
31177c478bd9Sstevel@tonic-gate if (queue_flag) {
31187c478bd9Sstevel@tonic-gate put(q, mp);
3119125a8fd9SSiddheshwar Mahesh return (RPC_SUCCESS);
3120125a8fd9SSiddheshwar Mahesh
31217c478bd9Sstevel@tonic-gate }
31227c478bd9Sstevel@tonic-gate
31237c478bd9Sstevel@tonic-gate /*
31247c478bd9Sstevel@tonic-gate * Set up calls for RPC requests (with XID != 0) on the hash
31257c478bd9Sstevel@tonic-gate * queue for fast lookups and place other calls (i.e.
31267c478bd9Sstevel@tonic-gate * connection management) on the linked list.
31277c478bd9Sstevel@tonic-gate */
31287c478bd9Sstevel@tonic-gate if (xid != 0) {
31297c478bd9Sstevel@tonic-gate RPCLOG(64, "clnt_dispatch_send: putting xid 0x%x on "
31307c478bd9Sstevel@tonic-gate "dispatch list\n", xid);
31317c478bd9Sstevel@tonic-gate e->call_hash = call_hash(xid, clnt_cots_hash_size);
31327c478bd9Sstevel@tonic-gate e->call_bucket = &cots_call_ht[e->call_hash];
31337c478bd9Sstevel@tonic-gate call_table_enter(e);
31347c478bd9Sstevel@tonic-gate } else {
31357c478bd9Sstevel@tonic-gate mutex_enter(&clnt_pending_lock);
31367c478bd9Sstevel@tonic-gate if (clnt_pending)
31377c478bd9Sstevel@tonic-gate clnt_pending->call_prev = e;
31387c478bd9Sstevel@tonic-gate e->call_next = clnt_pending;
31397c478bd9Sstevel@tonic-gate e->call_prev = NULL;
31407c478bd9Sstevel@tonic-gate clnt_pending = e;
31417c478bd9Sstevel@tonic-gate mutex_exit(&clnt_pending_lock);
31427c478bd9Sstevel@tonic-gate }
31437c478bd9Sstevel@tonic-gate
31447c478bd9Sstevel@tonic-gate put(q, mp);
3145125a8fd9SSiddheshwar Mahesh return (RPC_SUCCESS);
31467c478bd9Sstevel@tonic-gate }
31477c478bd9Sstevel@tonic-gate
31487c478bd9Sstevel@tonic-gate /*
31497c478bd9Sstevel@tonic-gate * Called by rpcmod to notify a client with a clnt_pending call that its reply
31507c478bd9Sstevel@tonic-gate * has arrived. If we can't find a client waiting for this reply, we log
31517c478bd9Sstevel@tonic-gate * the error and return.
31527c478bd9Sstevel@tonic-gate */
31537c478bd9Sstevel@tonic-gate bool_t
clnt_dispatch_notify(mblk_t * mp,zoneid_t zoneid)31547c478bd9Sstevel@tonic-gate clnt_dispatch_notify(mblk_t *mp, zoneid_t zoneid)
31557c478bd9Sstevel@tonic-gate {
31567c478bd9Sstevel@tonic-gate calllist_t *e = NULL;
31577c478bd9Sstevel@tonic-gate call_table_t *chtp;
31587c478bd9Sstevel@tonic-gate uint32_t xid;
31597c478bd9Sstevel@tonic-gate uint_t hash;
31607c478bd9Sstevel@tonic-gate
31617c478bd9Sstevel@tonic-gate if ((IS_P2ALIGNED(mp->b_rptr, sizeof (uint32_t))) &&
31627c478bd9Sstevel@tonic-gate (mp->b_wptr - mp->b_rptr) >= sizeof (xid))
31637c478bd9Sstevel@tonic-gate xid = *((uint32_t *)mp->b_rptr);
31647c478bd9Sstevel@tonic-gate else {
31657c478bd9Sstevel@tonic-gate int i = 0;
31667c478bd9Sstevel@tonic-gate unsigned char *p = (unsigned char *)&xid;
31677c478bd9Sstevel@tonic-gate unsigned char *rptr;
31687c478bd9Sstevel@tonic-gate mblk_t *tmp = mp;
31697c478bd9Sstevel@tonic-gate
31707c478bd9Sstevel@tonic-gate /*
31717c478bd9Sstevel@tonic-gate * Copy the xid, byte-by-byte into xid.
31727c478bd9Sstevel@tonic-gate */
31737c478bd9Sstevel@tonic-gate while (tmp) {
31747c478bd9Sstevel@tonic-gate rptr = tmp->b_rptr;
31757c478bd9Sstevel@tonic-gate while (rptr < tmp->b_wptr) {
31767c478bd9Sstevel@tonic-gate *p++ = *rptr++;
31777c478bd9Sstevel@tonic-gate if (++i >= sizeof (xid))
31787c478bd9Sstevel@tonic-gate goto done_xid_copy;
31797c478bd9Sstevel@tonic-gate }
31807c478bd9Sstevel@tonic-gate tmp = tmp->b_cont;
31817c478bd9Sstevel@tonic-gate }
31827c478bd9Sstevel@tonic-gate
31837c478bd9Sstevel@tonic-gate /*
31847c478bd9Sstevel@tonic-gate * If we got here, we ran out of mblk space before the
31857c478bd9Sstevel@tonic-gate * xid could be copied.
31867c478bd9Sstevel@tonic-gate */
31877c478bd9Sstevel@tonic-gate ASSERT(tmp == NULL && i < sizeof (xid));
31887c478bd9Sstevel@tonic-gate
31897c478bd9Sstevel@tonic-gate RPCLOG0(1,
31907c478bd9Sstevel@tonic-gate "clnt_dispatch_notify: message less than size of xid\n");
31917c478bd9Sstevel@tonic-gate return (FALSE);
31927c478bd9Sstevel@tonic-gate
31937c478bd9Sstevel@tonic-gate }
31947c478bd9Sstevel@tonic-gate done_xid_copy:
31957c478bd9Sstevel@tonic-gate
31967c478bd9Sstevel@tonic-gate hash = call_hash(xid, clnt_cots_hash_size);
31977c478bd9Sstevel@tonic-gate chtp = &cots_call_ht[hash];
31987c478bd9Sstevel@tonic-gate /* call_table_find returns with the hash bucket locked */
31997c478bd9Sstevel@tonic-gate call_table_find(chtp, xid, e);
32007c478bd9Sstevel@tonic-gate
32017c478bd9Sstevel@tonic-gate if (e != NULL) {
32027c478bd9Sstevel@tonic-gate /*
32037c478bd9Sstevel@tonic-gate * Found thread waiting for this reply
32047c478bd9Sstevel@tonic-gate */
32057c478bd9Sstevel@tonic-gate mutex_enter(&e->call_lock);
32068ffff9fdSgt29601
32078ffff9fdSgt29601 /*
32088ffff9fdSgt29601 * verify that the reply is coming in on
32098ffff9fdSgt29601 * the same zone that it was sent from.
32108ffff9fdSgt29601 */
32118ffff9fdSgt29601 if (e->call_zoneid != zoneid) {
32128ffff9fdSgt29601 mutex_exit(&e->call_lock);
32138ffff9fdSgt29601 mutex_exit(&chtp->ct_lock);
32148c3630f0SGerald Thornbrugh RPCLOG0(1, "clnt_dispatch_notify: incorrect zoneid\n");
32158ffff9fdSgt29601 return (FALSE);
32168ffff9fdSgt29601 }
32178ffff9fdSgt29601
32187c478bd9Sstevel@tonic-gate if (e->call_reply)
32197c478bd9Sstevel@tonic-gate /*
32207c478bd9Sstevel@tonic-gate * This can happen under the following scenario:
32217c478bd9Sstevel@tonic-gate * clnt_cots_kcallit() times out on the response,
32227c478bd9Sstevel@tonic-gate * rfscall() repeats the CLNT_CALL() with
32237c478bd9Sstevel@tonic-gate * the same xid, clnt_cots_kcallit() sends the retry,
32247c478bd9Sstevel@tonic-gate * thereby putting the clnt handle on the pending list,
32257c478bd9Sstevel@tonic-gate * the first response arrives, signalling the thread
32267c478bd9Sstevel@tonic-gate * in clnt_cots_kcallit(). Before that thread is
32277c478bd9Sstevel@tonic-gate * dispatched, the second response arrives as well,
32287c478bd9Sstevel@tonic-gate * and clnt_dispatch_notify still finds the handle on
32297c478bd9Sstevel@tonic-gate * the pending list, with call_reply set. So free the
32307c478bd9Sstevel@tonic-gate * old reply now.
32317c478bd9Sstevel@tonic-gate *
32327c478bd9Sstevel@tonic-gate * It is also possible for a response intended for
32337c478bd9Sstevel@tonic-gate * an RPC call with a different xid to reside here.
32347c478bd9Sstevel@tonic-gate * This can happen if the thread that owned this
32357c478bd9Sstevel@tonic-gate * client handle prior to the current owner bailed
32367c478bd9Sstevel@tonic-gate * out and left its call record on the dispatch
32377c478bd9Sstevel@tonic-gate * queue. A window exists where the response can
32387c478bd9Sstevel@tonic-gate * arrive before the current owner dispatches its
32397c478bd9Sstevel@tonic-gate * RPC call.
32407c478bd9Sstevel@tonic-gate *
32417c478bd9Sstevel@tonic-gate * In any case, this is the very last point where we
32427c478bd9Sstevel@tonic-gate * can safely check the call_reply field before
32437c478bd9Sstevel@tonic-gate * placing the new response there.
32447c478bd9Sstevel@tonic-gate */
32457c478bd9Sstevel@tonic-gate freemsg(e->call_reply);
32467c478bd9Sstevel@tonic-gate e->call_reply = mp;
32477c478bd9Sstevel@tonic-gate e->call_status = RPC_SUCCESS;
32487c478bd9Sstevel@tonic-gate e->call_notified = TRUE;
32497c478bd9Sstevel@tonic-gate cv_signal(&e->call_cv);
32507c478bd9Sstevel@tonic-gate mutex_exit(&e->call_lock);
32517c478bd9Sstevel@tonic-gate mutex_exit(&chtp->ct_lock);
32527c478bd9Sstevel@tonic-gate return (TRUE);
32537c478bd9Sstevel@tonic-gate } else {
32547c478bd9Sstevel@tonic-gate zone_t *zone;
32557c478bd9Sstevel@tonic-gate struct rpcstat *rpcstat;
32567c478bd9Sstevel@tonic-gate
32577c478bd9Sstevel@tonic-gate mutex_exit(&chtp->ct_lock);
32587c478bd9Sstevel@tonic-gate RPCLOG(65, "clnt_dispatch_notify: no caller for reply 0x%x\n",
32597c478bd9Sstevel@tonic-gate xid);
32607c478bd9Sstevel@tonic-gate /*
32617c478bd9Sstevel@tonic-gate * This is unfortunate, but we need to lookup the zone so we
32627c478bd9Sstevel@tonic-gate * can increment its "rcbadxids" counter.
32637c478bd9Sstevel@tonic-gate */
32647c478bd9Sstevel@tonic-gate zone = zone_find_by_id(zoneid);
32657c478bd9Sstevel@tonic-gate if (zone == NULL) {
32667c478bd9Sstevel@tonic-gate /*
32677c478bd9Sstevel@tonic-gate * The zone went away...
32687c478bd9Sstevel@tonic-gate */
32697c478bd9Sstevel@tonic-gate return (FALSE);
32707c478bd9Sstevel@tonic-gate }
32717c478bd9Sstevel@tonic-gate rpcstat = zone_getspecific(rpcstat_zone_key, zone);
32727c478bd9Sstevel@tonic-gate if (zone_status_get(zone) >= ZONE_IS_SHUTTING_DOWN) {
32737c478bd9Sstevel@tonic-gate /*
32747c478bd9Sstevel@tonic-gate * Not interested
32757c478bd9Sstevel@tonic-gate */
32767c478bd9Sstevel@tonic-gate zone_rele(zone);
32777c478bd9Sstevel@tonic-gate return (FALSE);
32787c478bd9Sstevel@tonic-gate }
32797c478bd9Sstevel@tonic-gate COTSRCSTAT_INCR(rpcstat->rpc_cots_client, rcbadxids);
32807c478bd9Sstevel@tonic-gate zone_rele(zone);
32817c478bd9Sstevel@tonic-gate }
32827c478bd9Sstevel@tonic-gate return (FALSE);
32837c478bd9Sstevel@tonic-gate }
32847c478bd9Sstevel@tonic-gate
32857c478bd9Sstevel@tonic-gate /*
32867c478bd9Sstevel@tonic-gate * Called by rpcmod when a non-data indication arrives. The ones in which we
32877c478bd9Sstevel@tonic-gate * are interested are connection indications and options acks. We dispatch
32887c478bd9Sstevel@tonic-gate * based on the queue the indication came in on. If we are not interested in
32897c478bd9Sstevel@tonic-gate * what came in, we return false to rpcmod, who will then pass it upstream.
32907c478bd9Sstevel@tonic-gate */
32917c478bd9Sstevel@tonic-gate bool_t
clnt_dispatch_notifyconn(queue_t * q,mblk_t * mp)32927c478bd9Sstevel@tonic-gate clnt_dispatch_notifyconn(queue_t *q, mblk_t *mp)
32937c478bd9Sstevel@tonic-gate {
32947c478bd9Sstevel@tonic-gate calllist_t *e;
32957c478bd9Sstevel@tonic-gate int type;
32967c478bd9Sstevel@tonic-gate
32977c478bd9Sstevel@tonic-gate ASSERT((q->q_flag & QREADR) == 0);
32987c478bd9Sstevel@tonic-gate
32997c478bd9Sstevel@tonic-gate type = ((union T_primitives *)mp->b_rptr)->type;
33007c478bd9Sstevel@tonic-gate RPCLOG(8, "clnt_dispatch_notifyconn: prim type: [%s]\n",
33017c478bd9Sstevel@tonic-gate rpc_tpiprim2name(type));
33027c478bd9Sstevel@tonic-gate mutex_enter(&clnt_pending_lock);
33037c478bd9Sstevel@tonic-gate for (e = clnt_pending; /* NO CONDITION */; e = e->call_next) {
33047c478bd9Sstevel@tonic-gate if (e == NULL) {
33057c478bd9Sstevel@tonic-gate mutex_exit(&clnt_pending_lock);
33067c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_dispatch_notifyconn: no one waiting "
33077c478bd9Sstevel@tonic-gate "for connection on queue 0x%p\n", (void *)q);
33087c478bd9Sstevel@tonic-gate return (FALSE);
33097c478bd9Sstevel@tonic-gate }
33107c478bd9Sstevel@tonic-gate if (e->call_wq == q)
33117c478bd9Sstevel@tonic-gate break;
33127c478bd9Sstevel@tonic-gate }
33137c478bd9Sstevel@tonic-gate
33147c478bd9Sstevel@tonic-gate switch (type) {
33157c478bd9Sstevel@tonic-gate case T_CONN_CON:
33167c478bd9Sstevel@tonic-gate /*
33177c478bd9Sstevel@tonic-gate * The transport is now connected, send a T_INFO_REQ to get
33187c478bd9Sstevel@tonic-gate * the tidu size.
33197c478bd9Sstevel@tonic-gate */
33207c478bd9Sstevel@tonic-gate mutex_exit(&clnt_pending_lock);
33217c478bd9Sstevel@tonic-gate ASSERT(mp->b_datap->db_lim - mp->b_datap->db_base >=
33227c478bd9Sstevel@tonic-gate sizeof (struct T_info_req));
33237c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_datap->db_base;
33247c478bd9Sstevel@tonic-gate ((union T_primitives *)mp->b_rptr)->type = T_INFO_REQ;
33257c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (struct T_info_req);
33267c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PCPROTO;
33277c478bd9Sstevel@tonic-gate put(q, mp);
33287c478bd9Sstevel@tonic-gate return (TRUE);
33297c478bd9Sstevel@tonic-gate case T_INFO_ACK:
33307c478bd9Sstevel@tonic-gate case T_OPTMGMT_ACK:
33317c478bd9Sstevel@tonic-gate e->call_status = RPC_SUCCESS;
33327c478bd9Sstevel@tonic-gate e->call_reply = mp;
33337c478bd9Sstevel@tonic-gate e->call_notified = TRUE;
33347c478bd9Sstevel@tonic-gate cv_signal(&e->call_cv);
33357c478bd9Sstevel@tonic-gate break;
33367c478bd9Sstevel@tonic-gate case T_ERROR_ACK:
33377c478bd9Sstevel@tonic-gate e->call_status = RPC_CANTCONNECT;
33387c478bd9Sstevel@tonic-gate e->call_reply = mp;
33397c478bd9Sstevel@tonic-gate e->call_notified = TRUE;
33407c478bd9Sstevel@tonic-gate cv_signal(&e->call_cv);
33417c478bd9Sstevel@tonic-gate break;
33427c478bd9Sstevel@tonic-gate case T_OK_ACK:
33437c478bd9Sstevel@tonic-gate /*
33447c478bd9Sstevel@tonic-gate * Great, but we are really waiting for a T_CONN_CON
33457c478bd9Sstevel@tonic-gate */
33467c478bd9Sstevel@tonic-gate freemsg(mp);
33477c478bd9Sstevel@tonic-gate break;
33487c478bd9Sstevel@tonic-gate default:
33497c478bd9Sstevel@tonic-gate mutex_exit(&clnt_pending_lock);
33507c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_dispatch_notifyconn: bad type %d\n", type);
33517c478bd9Sstevel@tonic-gate return (FALSE);
33527c478bd9Sstevel@tonic-gate }
33537c478bd9Sstevel@tonic-gate
33547c478bd9Sstevel@tonic-gate mutex_exit(&clnt_pending_lock);
33557c478bd9Sstevel@tonic-gate return (TRUE);
33567c478bd9Sstevel@tonic-gate }
33577c478bd9Sstevel@tonic-gate
33587c478bd9Sstevel@tonic-gate /*
33597c478bd9Sstevel@tonic-gate * Called by rpcmod when the transport is (or should be) going away. Informs
33607c478bd9Sstevel@tonic-gate * all callers waiting for replies and marks the entry in the connection
33617c478bd9Sstevel@tonic-gate * manager's list as unconnected, and either closing (close handshake in
33627c478bd9Sstevel@tonic-gate * progress) or dead.
33637c478bd9Sstevel@tonic-gate */
33647c478bd9Sstevel@tonic-gate void
clnt_dispatch_notifyall(queue_t * q,int32_t msg_type,int32_t reason)33657c478bd9Sstevel@tonic-gate clnt_dispatch_notifyall(queue_t *q, int32_t msg_type, int32_t reason)
33667c478bd9Sstevel@tonic-gate {
33677c478bd9Sstevel@tonic-gate calllist_t *e;
33687c478bd9Sstevel@tonic-gate call_table_t *ctp;
33697c478bd9Sstevel@tonic-gate struct cm_xprt *cm_entry;
33707c478bd9Sstevel@tonic-gate int have_connmgr_lock;
33717c478bd9Sstevel@tonic-gate int i;
33727c478bd9Sstevel@tonic-gate
33737c478bd9Sstevel@tonic-gate ASSERT((q->q_flag & QREADR) == 0);
33747c478bd9Sstevel@tonic-gate
33757c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_dispatch_notifyall on queue %p", (void *)q);
33767c478bd9Sstevel@tonic-gate RPCLOG(1, " received a notifcation prim type [%s]",
33777c478bd9Sstevel@tonic-gate rpc_tpiprim2name(msg_type));
33787c478bd9Sstevel@tonic-gate RPCLOG(1, " and reason %d\n", reason);
33797c478bd9Sstevel@tonic-gate
33807c478bd9Sstevel@tonic-gate /*
33817c478bd9Sstevel@tonic-gate * Find the transport entry in the connection manager's list, close
33827c478bd9Sstevel@tonic-gate * the transport and delete the entry. In the case where rpcmod's
33837c478bd9Sstevel@tonic-gate * idle timer goes off, it sends us a T_ORDREL_REQ, indicating we
33847c478bd9Sstevel@tonic-gate * should gracefully close the connection.
33857c478bd9Sstevel@tonic-gate */
33867c478bd9Sstevel@tonic-gate have_connmgr_lock = 1;
33877c478bd9Sstevel@tonic-gate mutex_enter(&connmgr_lock);
33887c478bd9Sstevel@tonic-gate for (cm_entry = cm_hd; cm_entry; cm_entry = cm_entry->x_next) {
33897c478bd9Sstevel@tonic-gate ASSERT(cm_entry != cm_entry->x_next);
33907c478bd9Sstevel@tonic-gate if (cm_entry->x_wq == q) {
33917c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&connmgr_lock));
33927c478bd9Sstevel@tonic-gate ASSERT(have_connmgr_lock == 1);
33937c478bd9Sstevel@tonic-gate switch (msg_type) {
33947c478bd9Sstevel@tonic-gate case T_ORDREL_REQ:
33957c478bd9Sstevel@tonic-gate
33967c478bd9Sstevel@tonic-gate if (cm_entry->x_dead) {
33977c478bd9Sstevel@tonic-gate RPCLOG(1, "idle timeout on dead "
33987c478bd9Sstevel@tonic-gate "connection: %p\n",
33997c478bd9Sstevel@tonic-gate (void *)cm_entry);
34007c478bd9Sstevel@tonic-gate if (clnt_stop_idle != NULL)
34017c478bd9Sstevel@tonic-gate (*clnt_stop_idle)(q);
34027c478bd9Sstevel@tonic-gate break;
34037c478bd9Sstevel@tonic-gate }
34047c478bd9Sstevel@tonic-gate
34057c478bd9Sstevel@tonic-gate /*
34067c478bd9Sstevel@tonic-gate * Only mark the connection as dead if it is
34077c478bd9Sstevel@tonic-gate * connected and idle.
34087c478bd9Sstevel@tonic-gate * An unconnected connection has probably
34097c478bd9Sstevel@tonic-gate * gone idle because the server is down,
34107c478bd9Sstevel@tonic-gate * and when it comes back up there will be
34117c478bd9Sstevel@tonic-gate * retries that need to use that connection.
34127c478bd9Sstevel@tonic-gate */
34137c478bd9Sstevel@tonic-gate if (cm_entry->x_connected ||
34147c478bd9Sstevel@tonic-gate cm_entry->x_doomed) {
34157c478bd9Sstevel@tonic-gate if (cm_entry->x_ordrel) {
34168ffff9fdSgt29601 if (cm_entry->x_closing ==
34178ffff9fdSgt29601 TRUE) {
34187c478bd9Sstevel@tonic-gate /*
34198ffff9fdSgt29601 * The connection is
34208ffff9fdSgt29601 * obviously wedged due
34218ffff9fdSgt29601 * to a bug or problem
34228ffff9fdSgt29601 * with the transport.
34238ffff9fdSgt29601 * Mark it as dead.
34248ffff9fdSgt29601 * Otherwise we can
34258ffff9fdSgt29601 * leak connections.
34267c478bd9Sstevel@tonic-gate */
34277c478bd9Sstevel@tonic-gate cm_entry->x_dead = TRUE;
34288ffff9fdSgt29601 mutex_exit(
34298ffff9fdSgt29601 &connmgr_lock);
34307c478bd9Sstevel@tonic-gate have_connmgr_lock = 0;
34318ffff9fdSgt29601 if (clnt_stop_idle !=
34328ffff9fdSgt29601 NULL)
34337c478bd9Sstevel@tonic-gate (*clnt_stop_idle)(q);
34347c478bd9Sstevel@tonic-gate break;
34357c478bd9Sstevel@tonic-gate }
34367c478bd9Sstevel@tonic-gate cm_entry->x_closing = TRUE;
34377c478bd9Sstevel@tonic-gate connmgr_sndrel(cm_entry);
34387c478bd9Sstevel@tonic-gate have_connmgr_lock = 0;
34397c478bd9Sstevel@tonic-gate } else {
34407c478bd9Sstevel@tonic-gate cm_entry->x_dead = TRUE;
34417c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
34427c478bd9Sstevel@tonic-gate have_connmgr_lock = 0;
34437c478bd9Sstevel@tonic-gate if (clnt_stop_idle != NULL)
34447c478bd9Sstevel@tonic-gate (*clnt_stop_idle)(q);
34457c478bd9Sstevel@tonic-gate }
34467c478bd9Sstevel@tonic-gate } else {
34477c478bd9Sstevel@tonic-gate /*
34487c478bd9Sstevel@tonic-gate * We don't mark the connection
34497c478bd9Sstevel@tonic-gate * as dead, but we turn off the
34507c478bd9Sstevel@tonic-gate * idle timer.
34517c478bd9Sstevel@tonic-gate */
34527c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
34537c478bd9Sstevel@tonic-gate have_connmgr_lock = 0;
34547c478bd9Sstevel@tonic-gate if (clnt_stop_idle != NULL)
34557c478bd9Sstevel@tonic-gate (*clnt_stop_idle)(q);
34567c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_dispatch_notifyall:"
34577c478bd9Sstevel@tonic-gate " ignoring timeout from rpcmod"
34587c478bd9Sstevel@tonic-gate " (q %p) because we are not "
34597c478bd9Sstevel@tonic-gate " connected\n", (void *)q);
34607c478bd9Sstevel@tonic-gate }
34617c478bd9Sstevel@tonic-gate break;
34627c478bd9Sstevel@tonic-gate case T_ORDREL_IND:
34637c478bd9Sstevel@tonic-gate /*
34647c478bd9Sstevel@tonic-gate * If this entry is marked closing, then we are
34657c478bd9Sstevel@tonic-gate * completing a close handshake, and the
34667c478bd9Sstevel@tonic-gate * connection is dead. Otherwise, the server is
34677c478bd9Sstevel@tonic-gate * trying to close. Since the server will not
34687c478bd9Sstevel@tonic-gate * be sending any more RPC replies, we abort
34697c478bd9Sstevel@tonic-gate * the connection, including flushing
34707c478bd9Sstevel@tonic-gate * any RPC requests that are in-transit.
347130f84f37SDai Ngo * In either case, mark the entry as dead so
347230f84f37SDai Ngo * that it can be closed by the connection
347330f84f37SDai Ngo * manager's garbage collector.
34747c478bd9Sstevel@tonic-gate */
34757c478bd9Sstevel@tonic-gate cm_entry->x_dead = TRUE;
347630f84f37SDai Ngo if (cm_entry->x_closing) {
34777c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
34787c478bd9Sstevel@tonic-gate have_connmgr_lock = 0;
34797c478bd9Sstevel@tonic-gate if (clnt_stop_idle != NULL)
34807c478bd9Sstevel@tonic-gate (*clnt_stop_idle)(q);
34817c478bd9Sstevel@tonic-gate } else {
34827c478bd9Sstevel@tonic-gate /*
34837c478bd9Sstevel@tonic-gate * if we're getting a disconnect
34847c478bd9Sstevel@tonic-gate * before we've finished our
34857c478bd9Sstevel@tonic-gate * connect attempt, mark it for
34867c478bd9Sstevel@tonic-gate * later processing
34877c478bd9Sstevel@tonic-gate */
34887c478bd9Sstevel@tonic-gate if (cm_entry->x_thread)
34897c478bd9Sstevel@tonic-gate cm_entry->x_early_disc = TRUE;
34907c478bd9Sstevel@tonic-gate else
34917c478bd9Sstevel@tonic-gate cm_entry->x_connected = FALSE;
34927c478bd9Sstevel@tonic-gate cm_entry->x_waitdis = TRUE;
34937c478bd9Sstevel@tonic-gate connmgr_snddis(cm_entry);
34947c478bd9Sstevel@tonic-gate have_connmgr_lock = 0;
34957c478bd9Sstevel@tonic-gate }
34967c478bd9Sstevel@tonic-gate break;
34977c478bd9Sstevel@tonic-gate
34987c478bd9Sstevel@tonic-gate case T_ERROR_ACK:
34997c478bd9Sstevel@tonic-gate case T_OK_ACK:
35007c478bd9Sstevel@tonic-gate cm_entry->x_waitdis = FALSE;
35017c478bd9Sstevel@tonic-gate cv_signal(&cm_entry->x_dis_cv);
35027c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
35037c478bd9Sstevel@tonic-gate return;
35047c478bd9Sstevel@tonic-gate
35057c478bd9Sstevel@tonic-gate case T_DISCON_REQ:
35067c478bd9Sstevel@tonic-gate if (cm_entry->x_thread)
35077c478bd9Sstevel@tonic-gate cm_entry->x_early_disc = TRUE;
35087c478bd9Sstevel@tonic-gate else
35097c478bd9Sstevel@tonic-gate cm_entry->x_connected = FALSE;
35107c478bd9Sstevel@tonic-gate cm_entry->x_waitdis = TRUE;
35117c478bd9Sstevel@tonic-gate
35127c478bd9Sstevel@tonic-gate connmgr_snddis(cm_entry);
35137c478bd9Sstevel@tonic-gate have_connmgr_lock = 0;
35147c478bd9Sstevel@tonic-gate break;
35157c478bd9Sstevel@tonic-gate
35167c478bd9Sstevel@tonic-gate case T_DISCON_IND:
35177c478bd9Sstevel@tonic-gate default:
35187c478bd9Sstevel@tonic-gate /*
35197c478bd9Sstevel@tonic-gate * if we're getting a disconnect before
35207c478bd9Sstevel@tonic-gate * we've finished our connect attempt,
35217c478bd9Sstevel@tonic-gate * mark it for later processing
35227c478bd9Sstevel@tonic-gate */
35237c478bd9Sstevel@tonic-gate if (cm_entry->x_closing) {
35247c478bd9Sstevel@tonic-gate cm_entry->x_dead = TRUE;
35257c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
35267c478bd9Sstevel@tonic-gate have_connmgr_lock = 0;
35277c478bd9Sstevel@tonic-gate if (clnt_stop_idle != NULL)
35287c478bd9Sstevel@tonic-gate (*clnt_stop_idle)(q);
35297c478bd9Sstevel@tonic-gate } else {
35307c478bd9Sstevel@tonic-gate if (cm_entry->x_thread) {
35317c478bd9Sstevel@tonic-gate cm_entry->x_early_disc = TRUE;
35327c478bd9Sstevel@tonic-gate } else {
35337c478bd9Sstevel@tonic-gate cm_entry->x_dead = TRUE;
35347c478bd9Sstevel@tonic-gate cm_entry->x_connected = FALSE;
35357c478bd9Sstevel@tonic-gate }
35367c478bd9Sstevel@tonic-gate }
35377c478bd9Sstevel@tonic-gate break;
35387c478bd9Sstevel@tonic-gate }
35397c478bd9Sstevel@tonic-gate break;
35407c478bd9Sstevel@tonic-gate }
35417c478bd9Sstevel@tonic-gate }
35427c478bd9Sstevel@tonic-gate
35437c478bd9Sstevel@tonic-gate if (have_connmgr_lock)
35447c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
35457c478bd9Sstevel@tonic-gate
35467c478bd9Sstevel@tonic-gate if (msg_type == T_ERROR_ACK || msg_type == T_OK_ACK) {
35477c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_dispatch_notifyall: (wq %p) could not find "
35487c478bd9Sstevel@tonic-gate "connmgr entry for discon ack\n", (void *)q);
35497c478bd9Sstevel@tonic-gate return;
35507c478bd9Sstevel@tonic-gate }
35517c478bd9Sstevel@tonic-gate
35527c478bd9Sstevel@tonic-gate /*
35537c478bd9Sstevel@tonic-gate * Then kick all the clnt_pending calls out of their wait. There
35547c478bd9Sstevel@tonic-gate * should be no clnt_pending calls in the case of rpcmod's idle
35557c478bd9Sstevel@tonic-gate * timer firing.
35567c478bd9Sstevel@tonic-gate */
35577c478bd9Sstevel@tonic-gate for (i = 0; i < clnt_cots_hash_size; i++) {
35587c478bd9Sstevel@tonic-gate ctp = &cots_call_ht[i];
35597c478bd9Sstevel@tonic-gate mutex_enter(&ctp->ct_lock);
35607c478bd9Sstevel@tonic-gate for (e = ctp->ct_call_next;
35617c478bd9Sstevel@tonic-gate e != (calllist_t *)ctp;
35627c478bd9Sstevel@tonic-gate e = e->call_next) {
35637c478bd9Sstevel@tonic-gate if (e->call_wq == q && e->call_notified == FALSE) {
35647c478bd9Sstevel@tonic-gate RPCLOG(1,
35657c478bd9Sstevel@tonic-gate "clnt_dispatch_notifyall for queue %p ",
35667c478bd9Sstevel@tonic-gate (void *)q);
35677c478bd9Sstevel@tonic-gate RPCLOG(1, "aborting clnt_pending call %p\n",
35687c478bd9Sstevel@tonic-gate (void *)e);
35697c478bd9Sstevel@tonic-gate
35707c478bd9Sstevel@tonic-gate if (msg_type == T_DISCON_IND)
35717c478bd9Sstevel@tonic-gate e->call_reason = reason;
35727c478bd9Sstevel@tonic-gate e->call_notified = TRUE;
35737c478bd9Sstevel@tonic-gate e->call_status = RPC_XPRTFAILED;
35747c478bd9Sstevel@tonic-gate cv_signal(&e->call_cv);
35757c478bd9Sstevel@tonic-gate }
35767c478bd9Sstevel@tonic-gate }
35777c478bd9Sstevel@tonic-gate mutex_exit(&ctp->ct_lock);
35787c478bd9Sstevel@tonic-gate }
35797c478bd9Sstevel@tonic-gate
35807c478bd9Sstevel@tonic-gate mutex_enter(&clnt_pending_lock);
35817c478bd9Sstevel@tonic-gate for (e = clnt_pending; e; e = e->call_next) {
35827c478bd9Sstevel@tonic-gate /*
35837c478bd9Sstevel@tonic-gate * Only signal those RPC handles that haven't been
35847c478bd9Sstevel@tonic-gate * signalled yet. Otherwise we can get a bogus call_reason.
35857c478bd9Sstevel@tonic-gate * This can happen if thread A is making a call over a
35867c478bd9Sstevel@tonic-gate * connection. If the server is killed, it will cause
35877c478bd9Sstevel@tonic-gate * reset, and reason will default to EIO as a result of
35887c478bd9Sstevel@tonic-gate * a T_ORDREL_IND. Thread B then attempts to recreate
35897c478bd9Sstevel@tonic-gate * the connection but gets a T_DISCON_IND. If we set the
35907c478bd9Sstevel@tonic-gate * call_reason code for all threads, then if thread A
35917c478bd9Sstevel@tonic-gate * hasn't been dispatched yet, it will get the wrong
35927c478bd9Sstevel@tonic-gate * reason. The bogus call_reason can make it harder to
35937c478bd9Sstevel@tonic-gate * discriminate between calls that fail because the
35947c478bd9Sstevel@tonic-gate * connection attempt failed versus those where the call
35957c478bd9Sstevel@tonic-gate * may have been executed on the server.
35967c478bd9Sstevel@tonic-gate */
35977c478bd9Sstevel@tonic-gate if (e->call_wq == q && e->call_notified == FALSE) {
35987c478bd9Sstevel@tonic-gate RPCLOG(1, "clnt_dispatch_notifyall for queue %p ",
35997c478bd9Sstevel@tonic-gate (void *)q);
36007c478bd9Sstevel@tonic-gate RPCLOG(1, " aborting clnt_pending call %p\n",
36017c478bd9Sstevel@tonic-gate (void *)e);
36027c478bd9Sstevel@tonic-gate
36037c478bd9Sstevel@tonic-gate if (msg_type == T_DISCON_IND)
36047c478bd9Sstevel@tonic-gate e->call_reason = reason;
36057c478bd9Sstevel@tonic-gate e->call_notified = TRUE;
36067c478bd9Sstevel@tonic-gate /*
36077c478bd9Sstevel@tonic-gate * Let the caller timeout, else he will retry
36087c478bd9Sstevel@tonic-gate * immediately.
36097c478bd9Sstevel@tonic-gate */
36107c478bd9Sstevel@tonic-gate e->call_status = RPC_XPRTFAILED;
36117c478bd9Sstevel@tonic-gate
36127c478bd9Sstevel@tonic-gate /*
36137c478bd9Sstevel@tonic-gate * We used to just signal those threads
36147c478bd9Sstevel@tonic-gate * waiting for a connection, (call_xid = 0).
36157c478bd9Sstevel@tonic-gate * That meant that threads waiting for a response
36167c478bd9Sstevel@tonic-gate * waited till their timeout expired. This
36177c478bd9Sstevel@tonic-gate * could be a long time if they've specified a
36187c478bd9Sstevel@tonic-gate * maximum timeout. (2^31 - 1). So we
36197c478bd9Sstevel@tonic-gate * Signal all threads now.
36207c478bd9Sstevel@tonic-gate */
36217c478bd9Sstevel@tonic-gate cv_signal(&e->call_cv);
36227c478bd9Sstevel@tonic-gate }
36237c478bd9Sstevel@tonic-gate }
36247c478bd9Sstevel@tonic-gate mutex_exit(&clnt_pending_lock);
36257c478bd9Sstevel@tonic-gate }
36267c478bd9Sstevel@tonic-gate
36277c478bd9Sstevel@tonic-gate
36287c478bd9Sstevel@tonic-gate /*ARGSUSED*/
36297c478bd9Sstevel@tonic-gate /*
36307c478bd9Sstevel@tonic-gate * after resuming a system that's been suspended for longer than the
36317c478bd9Sstevel@tonic-gate * NFS server's idle timeout (svc_idle_timeout for Solaris 2), rfscall()
36327c478bd9Sstevel@tonic-gate * generates "NFS server X not responding" and "NFS server X ok" messages;
36337c478bd9Sstevel@tonic-gate * here we reset inet connections to cause a re-connect and avoid those
36347c478bd9Sstevel@tonic-gate * NFS messages. see 4045054
36357c478bd9Sstevel@tonic-gate */
36367c478bd9Sstevel@tonic-gate boolean_t
connmgr_cpr_reset(void * arg,int code)36377c478bd9Sstevel@tonic-gate connmgr_cpr_reset(void *arg, int code)
36387c478bd9Sstevel@tonic-gate {
36397c478bd9Sstevel@tonic-gate struct cm_xprt *cxp;
36407c478bd9Sstevel@tonic-gate
36417c478bd9Sstevel@tonic-gate if (code == CB_CODE_CPR_CHKPT)
36427c478bd9Sstevel@tonic-gate return (B_TRUE);
36437c478bd9Sstevel@tonic-gate
36447c478bd9Sstevel@tonic-gate if (mutex_tryenter(&connmgr_lock) == 0)
36457c478bd9Sstevel@tonic-gate return (B_FALSE);
36467c478bd9Sstevel@tonic-gate for (cxp = cm_hd; cxp; cxp = cxp->x_next) {
36477c478bd9Sstevel@tonic-gate if ((cxp->x_family == AF_INET || cxp->x_family == AF_INET6) &&
36487c478bd9Sstevel@tonic-gate cxp->x_connected == TRUE) {
36497c478bd9Sstevel@tonic-gate if (cxp->x_thread)
36507c478bd9Sstevel@tonic-gate cxp->x_early_disc = TRUE;
36517c478bd9Sstevel@tonic-gate else
36527c478bd9Sstevel@tonic-gate cxp->x_connected = FALSE;
36537c478bd9Sstevel@tonic-gate cxp->x_needdis = TRUE;
36547c478bd9Sstevel@tonic-gate }
36557c478bd9Sstevel@tonic-gate }
36567c478bd9Sstevel@tonic-gate mutex_exit(&connmgr_lock);
36577c478bd9Sstevel@tonic-gate return (B_TRUE);
36587c478bd9Sstevel@tonic-gate }
36597c478bd9Sstevel@tonic-gate
36607c478bd9Sstevel@tonic-gate void
clnt_cots_stats_init(zoneid_t zoneid,struct rpc_cots_client ** statsp)36617c478bd9Sstevel@tonic-gate clnt_cots_stats_init(zoneid_t zoneid, struct rpc_cots_client **statsp)
36627c478bd9Sstevel@tonic-gate {
36637c478bd9Sstevel@tonic-gate
36647c478bd9Sstevel@tonic-gate *statsp = (struct rpc_cots_client *)rpcstat_zone_init_common(zoneid,
36657c478bd9Sstevel@tonic-gate "unix", "rpc_cots_client", (const kstat_named_t *)&cots_rcstat_tmpl,
36667c478bd9Sstevel@tonic-gate sizeof (cots_rcstat_tmpl));
36677c478bd9Sstevel@tonic-gate }
36687c478bd9Sstevel@tonic-gate
36697c478bd9Sstevel@tonic-gate void
clnt_cots_stats_fini(zoneid_t zoneid,struct rpc_cots_client ** statsp)36707c478bd9Sstevel@tonic-gate clnt_cots_stats_fini(zoneid_t zoneid, struct rpc_cots_client **statsp)
36717c478bd9Sstevel@tonic-gate {
36727c478bd9Sstevel@tonic-gate rpcstat_zone_fini_common(zoneid, "unix", "rpc_cots_client");
36737c478bd9Sstevel@tonic-gate kmem_free(*statsp, sizeof (cots_rcstat_tmpl));
36747c478bd9Sstevel@tonic-gate }
36757c478bd9Sstevel@tonic-gate
36767c478bd9Sstevel@tonic-gate void
clnt_cots_init(void)36777c478bd9Sstevel@tonic-gate clnt_cots_init(void)
36787c478bd9Sstevel@tonic-gate {
36797c478bd9Sstevel@tonic-gate mutex_init(&connmgr_lock, NULL, MUTEX_DEFAULT, NULL);
36807c478bd9Sstevel@tonic-gate mutex_init(&clnt_pending_lock, NULL, MUTEX_DEFAULT, NULL);
36817c478bd9Sstevel@tonic-gate
36827c478bd9Sstevel@tonic-gate if (clnt_cots_hash_size < DEFAULT_MIN_HASH_SIZE)
36837c478bd9Sstevel@tonic-gate clnt_cots_hash_size = DEFAULT_MIN_HASH_SIZE;
36847c478bd9Sstevel@tonic-gate
36857c478bd9Sstevel@tonic-gate cots_call_ht = call_table_init(clnt_cots_hash_size);
36867c478bd9Sstevel@tonic-gate zone_key_create(&zone_cots_key, NULL, NULL, clnt_zone_destroy);
36877c478bd9Sstevel@tonic-gate }
36887c478bd9Sstevel@tonic-gate
36897c478bd9Sstevel@tonic-gate void
clnt_cots_fini(void)36907c478bd9Sstevel@tonic-gate clnt_cots_fini(void)
36917c478bd9Sstevel@tonic-gate {
36927c478bd9Sstevel@tonic-gate (void) zone_key_delete(zone_cots_key);
36937c478bd9Sstevel@tonic-gate }
36947c478bd9Sstevel@tonic-gate
36957c478bd9Sstevel@tonic-gate /*
36967c478bd9Sstevel@tonic-gate * Wait for TPI ack, returns success only if expected ack is received
36977c478bd9Sstevel@tonic-gate * within timeout period.
36987c478bd9Sstevel@tonic-gate */
36997c478bd9Sstevel@tonic-gate
37007c478bd9Sstevel@tonic-gate static int
waitforack(calllist_t * e,t_scalar_t ack_prim,const struct timeval * waitp,bool_t nosignal)37017c478bd9Sstevel@tonic-gate waitforack(calllist_t *e, t_scalar_t ack_prim, const struct timeval *waitp,
37027c478bd9Sstevel@tonic-gate bool_t nosignal)
37037c478bd9Sstevel@tonic-gate {
37047c478bd9Sstevel@tonic-gate union T_primitives *tpr;
37057c478bd9Sstevel@tonic-gate clock_t timout;
37067c478bd9Sstevel@tonic-gate int cv_stat = 1;
37077c478bd9Sstevel@tonic-gate
37087c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&clnt_pending_lock));
37097c478bd9Sstevel@tonic-gate while (e->call_reply == NULL) {
37107c478bd9Sstevel@tonic-gate if (waitp != NULL) {
37117c478bd9Sstevel@tonic-gate timout = waitp->tv_sec * drv_usectohz(MICROSEC) +
3712d3d50737SRafael Vanoni drv_usectohz(waitp->tv_usec);
37137c478bd9Sstevel@tonic-gate if (nosignal)
3714d3d50737SRafael Vanoni cv_stat = cv_reltimedwait(&e->call_cv,
3715d3d50737SRafael Vanoni &clnt_pending_lock, timout, TR_CLOCK_TICK);
37167c478bd9Sstevel@tonic-gate else
3717d3d50737SRafael Vanoni cv_stat = cv_reltimedwait_sig(&e->call_cv,
3718d3d50737SRafael Vanoni &clnt_pending_lock, timout, TR_CLOCK_TICK);
37197c478bd9Sstevel@tonic-gate } else {
37207c478bd9Sstevel@tonic-gate if (nosignal)
37217c478bd9Sstevel@tonic-gate cv_wait(&e->call_cv, &clnt_pending_lock);
37227c478bd9Sstevel@tonic-gate else
37237c478bd9Sstevel@tonic-gate cv_stat = cv_wait_sig(&e->call_cv,
37247c478bd9Sstevel@tonic-gate &clnt_pending_lock);
37257c478bd9Sstevel@tonic-gate }
37267c478bd9Sstevel@tonic-gate if (cv_stat == -1)
37277c478bd9Sstevel@tonic-gate return (ETIME);
37287c478bd9Sstevel@tonic-gate if (cv_stat == 0)
37297c478bd9Sstevel@tonic-gate return (EINTR);
37306ec2b7e3Sgt29601 /*
37316ec2b7e3Sgt29601 * if we received an error from the server and we know a reply
37326ec2b7e3Sgt29601 * is not going to be sent, do not wait for the full timeout,
37336ec2b7e3Sgt29601 * return now.
37346ec2b7e3Sgt29601 */
37356ec2b7e3Sgt29601 if (e->call_status == RPC_XPRTFAILED)
37366ec2b7e3Sgt29601 return (e->call_reason);
37377c478bd9Sstevel@tonic-gate }
37387c478bd9Sstevel@tonic-gate tpr = (union T_primitives *)e->call_reply->b_rptr;
37397c478bd9Sstevel@tonic-gate if (tpr->type == ack_prim)
37407c478bd9Sstevel@tonic-gate return (0); /* Success */
37417c478bd9Sstevel@tonic-gate
37427c478bd9Sstevel@tonic-gate if (tpr->type == T_ERROR_ACK) {
37437c478bd9Sstevel@tonic-gate if (tpr->error_ack.TLI_error == TSYSERR)
37447c478bd9Sstevel@tonic-gate return (tpr->error_ack.UNIX_error);
37457c478bd9Sstevel@tonic-gate else
37467c478bd9Sstevel@tonic-gate return (t_tlitosyserr(tpr->error_ack.TLI_error));
37477c478bd9Sstevel@tonic-gate }
37487c478bd9Sstevel@tonic-gate
37497c478bd9Sstevel@tonic-gate return (EPROTO); /* unknown or unexpected primitive */
37507c478bd9Sstevel@tonic-gate }
3751