1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1676 jpk * Common Development and Distribution License (the "License"). 6 1676 jpk * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 8778 Erik * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel /* 27 0 stevel * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T 28 0 stevel * All Rights Reserved 29 0 stevel */ 30 0 stevel 31 0 stevel /* 32 0 stevel * Portions of this source code were derived from Berkeley 4.3 BSD 33 0 stevel * under license from the Regents of the University of California. 34 0 stevel */ 35 0 stevel 36 0 stevel 37 0 stevel /* 38 0 stevel * Implements a kernel based, client side RPC over Connection Oriented 39 0 stevel * Transports (COTS). 40 0 stevel */ 41 0 stevel 42 0 stevel /* 43 0 stevel * Much of this file has been re-written to let NFS work better over slow 44 0 stevel * transports. A description follows. 45 0 stevel * 46 0 stevel * One of the annoying things about kRPC/COTS is that it will temporarily 47 0 stevel * create more than one connection between a client and server. This 48 0 stevel * happens because when a connection is made, the end-points entry in the 49 0 stevel * linked list of connections (headed by cm_hd), is removed so that other 50 0 stevel * threads don't mess with it. Went ahead and bit the bullet by keeping 51 0 stevel * the endpoint on the connection list and introducing state bits, 52 0 stevel * condition variables etc. to the connection entry data structure (struct 53 0 stevel * cm_xprt). 54 0 stevel * 55 0 stevel * Here is a summary of the changes to cm-xprt: 56 0 stevel * 57 0 stevel * x_ctime is the timestamp of when the endpoint was last 58 0 stevel * connected or disconnected. If an end-point is ever disconnected 59 0 stevel * or re-connected, then any outstanding RPC request is presumed 60 0 stevel * lost, telling clnt_cots_kcallit that it needs to re-send the 61 0 stevel * request, not just wait for the original request's reply to 62 0 stevel * arrive. 63 0 stevel * 64 0 stevel * x_thread flag which tells us if a thread is doing a connection attempt. 65 0 stevel * 66 0 stevel * x_waitdis flag which tells us we are waiting a disconnect ACK. 67 0 stevel * 68 0 stevel * x_needdis flag which tells us we need to send a T_DISCONN_REQ 69 0 stevel * to kill the connection. 70 0 stevel * 71 0 stevel * x_needrel flag which tells us we need to send a T_ORDREL_REQ to 72 0 stevel * gracefully close the connection. 73 0 stevel * 74 0 stevel * #defined bitmasks for the all the b_* bits so that more 75 0 stevel * efficient (and at times less clumsy) masks can be used to 76 0 stevel * manipulated state in cases where multiple bits have to 77 0 stevel * set/cleared/checked in the same critical section. 78 0 stevel * 79 0 stevel * x_conn_cv and x_dis-_cv are new condition variables to let 80 0 stevel * threads knows when the connection attempt is done, and to let 81 0 stevel * the connecting thread know when the disconnect handshake is 82 0 stevel * done. 83 0 stevel * 84 0 stevel * Added the CONN_HOLD() macro so that all reference holds have the same 85 0 stevel * look and feel. 86 0 stevel * 87 0 stevel * In the private (cku_private) portion of the client handle, 88 0 stevel * 89 0 stevel * cku_flags replaces the cku_sent a boolean. cku_flags keeps 90 0 stevel * track of whether a request as been sent, and whether the 91 0 stevel * client's handles call record is on the dispatch list (so that 92 0 stevel * the reply can be matched by XID to the right client handle). 93 0 stevel * The idea of CKU_ONQUEUE is that we can exit clnt_cots_kcallit() 94 0 stevel * and still have the response find the right client handle so 95 0 stevel * that the retry of CLNT_CALL() gets the result. Testing, found 96 0 stevel * situations where if the timeout was increased, performance 97 0 stevel * degraded. This was due to us hitting a window where the thread 98 0 stevel * was back in rfscall() (probably printing server not responding) 99 0 stevel * while the response came back but no place to put it. 100 0 stevel * 101 0 stevel * cku_ctime is just a cache of x_ctime. If they match, 102 0 stevel * clnt_cots_kcallit() won't to send a retry (unless the maximum 103 0 stevel * receive count limit as been reached). If the don't match, then 104 0 stevel * we assume the request has been lost, and a retry of the request 105 0 stevel * is needed. 106 0 stevel * 107 0 stevel * cku_recv_attempts counts the number of receive count attempts 108 0 stevel * after one try is sent on the wire. 109 0 stevel * 110 0 stevel * Added the clnt_delay() routine so that interruptible and 111 0 stevel * noninterruptible delays are possible. 112 0 stevel * 113 0 stevel * CLNT_MIN_TIMEOUT has been bumped to 10 seconds from 3. This is used to 114 0 stevel * control how long the client delays before returned after getting 115 0 stevel * ECONNREFUSED. At 3 seconds, 8 client threads per mount really does bash 116 0 stevel * a server that may be booting and not yet started nfsd. 117 0 stevel * 118 0 stevel * CLNT_MAXRECV_WITHOUT_RETRY is a new macro (value of 3) (with a tunable) 119 0 stevel * Why don't we just wait forever (receive an infinite # of times)? 120 0 stevel * Because the server may have rebooted. More insidious is that some 121 0 stevel * servers (ours) will drop NFS/TCP requests in some cases. This is bad, 122 0 stevel * but it is a reality. 123 0 stevel * 124 0 stevel * The case of a server doing orderly release really messes up the 125 0 stevel * client's recovery, especially if the server's TCP implementation is 126 0 stevel * buggy. It was found was that the kRPC/COTS client was breaking some 127 0 stevel * TPI rules, such as not waiting for the acknowledgement of a 128 0 stevel * T_DISCON_REQ (hence the added case statements T_ERROR_ACK, T_OK_ACK and 129 0 stevel * T_DISCON_REQ in clnt_dispatch_notifyall()). 130 0 stevel * 131 0 stevel * One of things that we've seen is that a kRPC TCP endpoint goes into 132 0 stevel * TIMEWAIT and a thus a reconnect takes a long time to satisfy because 133 0 stevel * that the TIMEWAIT state takes a while to finish. If a server sends a 134 0 stevel * T_ORDREL_IND, there is little point in an RPC client doing a 135 0 stevel * T_ORDREL_REQ, because the RPC request isn't going to make it (the 136 0 stevel * server is saying that it won't accept any more data). So kRPC was 137 0 stevel * changed to send a T_DISCON_REQ when we get a T_ORDREL_IND. So now the 138 0 stevel * connection skips the TIMEWAIT state and goes straight to a bound state 139 0 stevel * that kRPC can quickly switch to connected. 140 0 stevel * 141 0 stevel * Code that issues TPI request must use waitforack() to wait for the 142 0 stevel * corresponding ack (assuming there is one) in any future modifications. 143 0 stevel * This works around problems that may be introduced by breaking TPI rules 144 0 stevel * (by submitting new calls before earlier requests have been acked) in the 145 0 stevel * case of a signal or other early return. waitforack() depends on 146 0 stevel * clnt_dispatch_notifyconn() to issue the wakeup when the ack 147 0 stevel * arrives, so adding new TPI calls may require corresponding changes 148 0 stevel * to clnt_dispatch_notifyconn(). Presently, the timeout period is based on 149 0 stevel * CLNT_MIN_TIMEOUT which is 10 seconds. If you modify this value, be sure 150 0 stevel * not to set it too low or TPI ACKS will be lost. 151 0 stevel */ 152 0 stevel 153 0 stevel #include <sys/param.h> 154 0 stevel #include <sys/types.h> 155 0 stevel #include <sys/user.h> 156 0 stevel #include <sys/systm.h> 157 0 stevel #include <sys/sysmacros.h> 158 0 stevel #include <sys/proc.h> 159 0 stevel #include <sys/socket.h> 160 0 stevel #include <sys/file.h> 161 0 stevel #include <sys/stream.h> 162 0 stevel #include <sys/strsubr.h> 163 0 stevel #include <sys/stropts.h> 164 0 stevel #include <sys/strsun.h> 165 0 stevel #include <sys/timod.h> 166 0 stevel #include <sys/tiuser.h> 167 0 stevel #include <sys/tihdr.h> 168 0 stevel #include <sys/t_kuser.h> 169 0 stevel #include <sys/fcntl.h> 170 0 stevel #include <sys/errno.h> 171 0 stevel #include <sys/kmem.h> 172 0 stevel #include <sys/debug.h> 173 0 stevel #include <sys/systm.h> 174 0 stevel #include <sys/kstat.h> 175 0 stevel #include <sys/t_lock.h> 176 0 stevel #include <sys/ddi.h> 177 0 stevel #include <sys/cmn_err.h> 178 0 stevel #include <sys/time.h> 179 0 stevel #include <sys/isa_defs.h> 180 0 stevel #include <sys/callb.h> 181 0 stevel #include <sys/sunddi.h> 182 0 stevel #include <sys/atomic.h> 183 8205 Siddheshwar #include <sys/sdt.h> 184 0 stevel 185 0 stevel #include <netinet/in.h> 186 0 stevel #include <netinet/tcp.h> 187 0 stevel 188 0 stevel #include <rpc/types.h> 189 0 stevel #include <rpc/xdr.h> 190 0 stevel #include <rpc/auth.h> 191 0 stevel #include <rpc/clnt.h> 192 0 stevel #include <rpc/rpc_msg.h> 193 0 stevel 194 0 stevel #define COTS_DEFAULT_ALLOCSIZE 2048 195 0 stevel 196 0 stevel #define WIRE_HDR_SIZE 20 /* serialized call header, sans proc number */ 197 0 stevel #define MSG_OFFSET 128 /* offset of call into the mblk */ 198 0 stevel 199 0 stevel const char *kinet_ntop6(uchar_t *, char *, size_t); 200 0 stevel 201 0 stevel static int clnt_cots_ksettimers(CLIENT *, struct rpc_timers *, 202 0 stevel struct rpc_timers *, int, void(*)(int, int, caddr_t), caddr_t, uint32_t); 203 0 stevel static enum clnt_stat clnt_cots_kcallit(CLIENT *, rpcproc_t, xdrproc_t, 204 0 stevel caddr_t, xdrproc_t, caddr_t, struct timeval); 205 0 stevel static void clnt_cots_kabort(CLIENT *); 206 0 stevel static void clnt_cots_kerror(CLIENT *, struct rpc_err *); 207 0 stevel static bool_t clnt_cots_kfreeres(CLIENT *, xdrproc_t, caddr_t); 208 0 stevel static void clnt_cots_kdestroy(CLIENT *); 209 0 stevel static bool_t clnt_cots_kcontrol(CLIENT *, int, char *); 210 0 stevel 211 0 stevel 212 0 stevel /* List of transports managed by the connection manager. */ 213 0 stevel struct cm_xprt { 214 0 stevel TIUSER *x_tiptr; /* transport handle */ 215 0 stevel queue_t *x_wq; /* send queue */ 216 0 stevel clock_t x_time; /* last time we handed this xprt out */ 217 0 stevel clock_t x_ctime; /* time we went to CONNECTED */ 218 0 stevel int x_tidu_size; /* TIDU size of this transport */ 219 0 stevel union { 220 0 stevel struct { 221 0 stevel unsigned int 222 0 stevel #ifdef _BIT_FIELDS_HTOL 223 0 stevel b_closing: 1, /* we've sent a ord rel on this conn */ 224 0 stevel b_dead: 1, /* transport is closed or disconn */ 225 0 stevel b_doomed: 1, /* too many conns, let this go idle */ 226 0 stevel b_connected: 1, /* this connection is connected */ 227 0 stevel 228 0 stevel b_ordrel: 1, /* do an orderly release? */ 229 0 stevel b_thread: 1, /* thread doing connect */ 230 0 stevel b_waitdis: 1, /* waiting for disconnect ACK */ 231 0 stevel b_needdis: 1, /* need T_DISCON_REQ */ 232 0 stevel 233 0 stevel b_needrel: 1, /* need T_ORDREL_REQ */ 234 0 stevel b_early_disc: 1, /* got a T_ORDREL_IND or T_DISCON_IND */ 235 0 stevel /* disconnect during connect */ 236 0 stevel 237 0 stevel b_pad: 22; 238 0 stevel 239 0 stevel #endif 240 0 stevel 241 0 stevel #ifdef _BIT_FIELDS_LTOH 242 0 stevel b_pad: 22, 243 0 stevel 244 0 stevel b_early_disc: 1, /* got a T_ORDREL_IND or T_DISCON_IND */ 245 0 stevel /* disconnect during connect */ 246 0 stevel b_needrel: 1, /* need T_ORDREL_REQ */ 247 0 stevel 248 0 stevel b_needdis: 1, /* need T_DISCON_REQ */ 249 0 stevel b_waitdis: 1, /* waiting for disconnect ACK */ 250 0 stevel b_thread: 1, /* thread doing connect */ 251 0 stevel b_ordrel: 1, /* do an orderly release? */ 252 0 stevel 253 0 stevel b_connected: 1, /* this connection is connected */ 254 0 stevel b_doomed: 1, /* too many conns, let this go idle */ 255 0 stevel b_dead: 1, /* transport is closed or disconn */ 256 0 stevel b_closing: 1; /* we've sent a ord rel on this conn */ 257 0 stevel #endif 258 0 stevel } bit; unsigned int word; 259 0 stevel 260 0 stevel #define x_closing x_state.bit.b_closing 261 0 stevel #define x_dead x_state.bit.b_dead 262 0 stevel #define x_doomed x_state.bit.b_doomed 263 0 stevel #define x_connected x_state.bit.b_connected 264 0 stevel 265 0 stevel #define x_ordrel x_state.bit.b_ordrel 266 0 stevel #define x_thread x_state.bit.b_thread 267 0 stevel #define x_waitdis x_state.bit.b_waitdis 268 0 stevel #define x_needdis x_state.bit.b_needdis 269 0 stevel 270 0 stevel #define x_needrel x_state.bit.b_needrel 271 0 stevel #define x_early_disc x_state.bit.b_early_disc 272 0 stevel 273 0 stevel #define x_state_flags x_state.word 274 0 stevel 275 0 stevel #define X_CLOSING 0x80000000 276 0 stevel #define X_DEAD 0x40000000 277 0 stevel #define X_DOOMED 0x20000000 278 0 stevel #define X_CONNECTED 0x10000000 279 0 stevel 280 0 stevel #define X_ORDREL 0x08000000 281 0 stevel #define X_THREAD 0x04000000 282 0 stevel #define X_WAITDIS 0x02000000 283 0 stevel #define X_NEEDDIS 0x01000000 284 0 stevel 285 0 stevel #define X_NEEDREL 0x00800000 286 0 stevel #define X_EARLYDISC 0x00400000 287 0 stevel 288 0 stevel #define X_BADSTATES (X_CLOSING | X_DEAD | X_DOOMED) 289 0 stevel 290 0 stevel } x_state; 291 0 stevel int x_ref; /* number of users of this xprt */ 292 0 stevel int x_family; /* address family of transport */ 293 0 stevel dev_t x_rdev; /* device number of transport */ 294 0 stevel struct cm_xprt *x_next; 295 0 stevel 296 0 stevel struct netbuf x_server; /* destination address */ 297 0 stevel struct netbuf x_src; /* src address (for retries) */ 298 0 stevel kmutex_t x_lock; /* lock on this entry */ 299 0 stevel kcondvar_t x_cv; /* to signal when can be closed */ 300 0 stevel kcondvar_t x_conn_cv; /* to signal when connection attempt */ 301 0 stevel /* is complete */ 302 0 stevel kstat_t *x_ksp; 303 0 stevel 304 0 stevel kcondvar_t x_dis_cv; /* to signal when disconnect attempt */ 305 0 stevel /* is complete */ 306 0 stevel zoneid_t x_zoneid; /* zone this xprt belongs to */ 307 0 stevel }; 308 0 stevel 309 0 stevel typedef struct cm_kstat_xprt { 310 0 stevel kstat_named_t x_wq; 311 0 stevel kstat_named_t x_server; 312 0 stevel kstat_named_t x_family; 313 0 stevel kstat_named_t x_rdev; 314 0 stevel kstat_named_t x_time; 315 0 stevel kstat_named_t x_state; 316 0 stevel kstat_named_t x_ref; 317 0 stevel kstat_named_t x_port; 318 0 stevel } cm_kstat_xprt_t; 319 0 stevel 320 0 stevel static cm_kstat_xprt_t cm_kstat_template = { 321 0 stevel { "write_queue", KSTAT_DATA_UINT32 }, 322 0 stevel { "server", KSTAT_DATA_STRING }, 323 0 stevel { "addr_family", KSTAT_DATA_UINT32 }, 324 0 stevel { "device", KSTAT_DATA_UINT32 }, 325 0 stevel { "time_stamp", KSTAT_DATA_UINT32 }, 326 0 stevel { "status", KSTAT_DATA_UINT32 }, 327 0 stevel { "ref_count", KSTAT_DATA_INT32 }, 328 0 stevel { "port", KSTAT_DATA_UINT32 }, 329 0 stevel }; 330 0 stevel 331 0 stevel /* 332 0 stevel * The inverse of this is connmgr_release(). 333 0 stevel */ 334 0 stevel #define CONN_HOLD(Cm_entry) {\ 335 0 stevel mutex_enter(&(Cm_entry)->x_lock); \ 336 0 stevel (Cm_entry)->x_ref++; \ 337 0 stevel mutex_exit(&(Cm_entry)->x_lock); \ 338 0 stevel } 339 0 stevel 340 0 stevel 341 0 stevel /* 342 0 stevel * Private data per rpc handle. This structure is allocated by 343 0 stevel * clnt_cots_kcreate, and freed by clnt_cots_kdestroy. 344 0 stevel */ 345 0 stevel typedef struct cku_private_s { 346 0 stevel CLIENT cku_client; /* client handle */ 347 0 stevel calllist_t cku_call; /* for dispatching calls */ 348 0 stevel struct rpc_err cku_err; /* error status */ 349 0 stevel 350 0 stevel struct netbuf cku_srcaddr; /* source address for retries */ 351 0 stevel int cku_addrfmly; /* for binding port */ 352 0 stevel struct netbuf cku_addr; /* remote address */ 353 0 stevel dev_t cku_device; /* device to use */ 354 0 stevel uint_t cku_flags; 355 0 stevel #define CKU_ONQUEUE 0x1 356 0 stevel #define CKU_SENT 0x2 357 0 stevel 358 0 stevel bool_t cku_progress; /* for CLSET_PROGRESS */ 359 0 stevel uint32_t cku_xid; /* current XID */ 360 0 stevel clock_t cku_ctime; /* time stamp of when */ 361 0 stevel /* connection was created */ 362 0 stevel uint_t cku_recv_attempts; 363 0 stevel XDR cku_outxdr; /* xdr routine for output */ 364 0 stevel XDR cku_inxdr; /* xdr routine for input */ 365 0 stevel char cku_rpchdr[WIRE_HDR_SIZE + 4]; 366 0 stevel /* pre-serialized rpc header */ 367 0 stevel 368 0 stevel uint_t cku_outbuflen; /* default output mblk length */ 369 0 stevel struct cred *cku_cred; /* credentials */ 370 0 stevel bool_t cku_nodelayonerr; 371 0 stevel /* for CLSET_NODELAYONERR */ 372 0 stevel int cku_useresvport; /* Use reserved port */ 373 0 stevel struct rpc_cots_client *cku_stats; /* stats for zone */ 374 0 stevel } cku_private_t; 375 0 stevel 376 0 stevel static struct cm_xprt *connmgr_wrapconnect(struct cm_xprt *, 377 0 stevel const struct timeval *, struct netbuf *, int, struct netbuf *, 378 8778 Erik struct rpc_err *, bool_t, bool_t, cred_t *); 379 0 stevel 380 0 stevel static bool_t connmgr_connect(struct cm_xprt *, queue_t *, struct netbuf *, 381 0 stevel int, calllist_t *, int *, bool_t reconnect, 382 8778 Erik const struct timeval *, bool_t, cred_t *); 383 0 stevel 384 10004 dai static void *connmgr_opt_getoff(mblk_t *mp, t_uscalar_t offset, 385 10004 dai t_uscalar_t length, uint_t align_size); 386 10004 dai static bool_t connmgr_setbufsz(calllist_t *e, queue_t *wq, cred_t *cr); 387 10004 dai static bool_t connmgr_getopt_int(queue_t *wq, int level, int name, int *val, 388 10004 dai calllist_t *e, cred_t *cr); 389 10004 dai static bool_t connmgr_setopt_int(queue_t *wq, int level, int name, int val, 390 10004 dai calllist_t *e, cred_t *cr); 391 8778 Erik static bool_t connmgr_setopt(queue_t *, int, int, calllist_t *, cred_t *cr); 392 0 stevel static void connmgr_sndrel(struct cm_xprt *); 393 0 stevel static void connmgr_snddis(struct cm_xprt *); 394 0 stevel static void connmgr_close(struct cm_xprt *); 395 0 stevel static void connmgr_release(struct cm_xprt *); 396 0 stevel static struct cm_xprt *connmgr_wrapget(struct netbuf *, const struct timeval *, 397 0 stevel cku_private_t *); 398 0 stevel 399 0 stevel static struct cm_xprt *connmgr_get(struct netbuf *, const struct timeval *, 400 0 stevel struct netbuf *, int, struct netbuf *, struct rpc_err *, dev_t, 401 8778 Erik bool_t, int, cred_t *); 402 0 stevel 403 0 stevel static void connmgr_cancelconn(struct cm_xprt *); 404 0 stevel static enum clnt_stat connmgr_cwait(struct cm_xprt *, const struct timeval *, 405 0 stevel bool_t); 406 0 stevel static void connmgr_dis_and_wait(struct cm_xprt *); 407 0 stevel 408 8205 Siddheshwar static int clnt_dispatch_send(queue_t *, mblk_t *, calllist_t *, uint_t, 409 0 stevel uint_t); 410 0 stevel 411 0 stevel static int clnt_delay(clock_t, bool_t); 412 0 stevel 413 0 stevel static int waitforack(calllist_t *, t_scalar_t, const struct timeval *, bool_t); 414 0 stevel 415 0 stevel /* 416 0 stevel * Operations vector for TCP/IP based RPC 417 0 stevel */ 418 0 stevel static struct clnt_ops tcp_ops = { 419 0 stevel clnt_cots_kcallit, /* do rpc call */ 420 0 stevel clnt_cots_kabort, /* abort call */ 421 0 stevel clnt_cots_kerror, /* return error status */ 422 0 stevel clnt_cots_kfreeres, /* free results */ 423 0 stevel clnt_cots_kdestroy, /* destroy rpc handle */ 424 0 stevel clnt_cots_kcontrol, /* the ioctl() of rpc */ 425 0 stevel clnt_cots_ksettimers, /* set retry timers */ 426 0 stevel }; 427 0 stevel 428 0 stevel static int rpc_kstat_instance = 0; /* keeps the current instance */ 429 0 stevel /* number for the next kstat_create */ 430 0 stevel 431 0 stevel static struct cm_xprt *cm_hd = NULL; 432 0 stevel static kmutex_t connmgr_lock; /* for connection mngr's list of transports */ 433 0 stevel 434 0 stevel extern kmutex_t clnt_max_msg_lock; 435 0 stevel 436 0 stevel static calllist_t *clnt_pending = NULL; 437 0 stevel extern kmutex_t clnt_pending_lock; 438 0 stevel 439 0 stevel static int clnt_cots_hash_size = DEFAULT_HASH_SIZE; 440 0 stevel 441 0 stevel static call_table_t *cots_call_ht; 442 0 stevel 443 0 stevel static const struct rpc_cots_client { 444 0 stevel kstat_named_t rccalls; 445 0 stevel kstat_named_t rcbadcalls; 446 0 stevel kstat_named_t rcbadxids; 447 0 stevel kstat_named_t rctimeouts; 448 0 stevel kstat_named_t rcnewcreds; 449 0 stevel kstat_named_t rcbadverfs; 450 0 stevel kstat_named_t rctimers; 451 0 stevel kstat_named_t rccantconn; 452 0 stevel kstat_named_t rcnomem; 453 0 stevel kstat_named_t rcintrs; 454 0 stevel } cots_rcstat_tmpl = { 455 0 stevel { "calls", KSTAT_DATA_UINT64 }, 456 0 stevel { "badcalls", KSTAT_DATA_UINT64 }, 457 0 stevel { "badxids", KSTAT_DATA_UINT64 }, 458 0 stevel { "timeouts", KSTAT_DATA_UINT64 }, 459 0 stevel { "newcreds", KSTAT_DATA_UINT64 }, 460 0 stevel { "badverfs", KSTAT_DATA_UINT64 }, 461 0 stevel { "timers", KSTAT_DATA_UINT64 }, 462 0 stevel { "cantconn", KSTAT_DATA_UINT64 }, 463 0 stevel { "nomem", KSTAT_DATA_UINT64 }, 464 0 stevel { "interrupts", KSTAT_DATA_UINT64 } 465 0 stevel }; 466 0 stevel 467 0 stevel #define COTSRCSTAT_INCR(p, x) \ 468 0 stevel atomic_add_64(&(p)->x.value.ui64, 1) 469 0 stevel 470 0 stevel #define CLNT_MAX_CONNS 1 /* concurrent connections between clnt/srvr */ 471 9806 dai int clnt_max_conns = CLNT_MAX_CONNS; 472 0 stevel 473 0 stevel #define CLNT_MIN_TIMEOUT 10 /* seconds to wait after we get a */ 474 0 stevel /* connection reset */ 475 0 stevel #define CLNT_MIN_CONNTIMEOUT 5 /* seconds to wait for a connection */ 476 0 stevel 477 0 stevel 478 9806 dai int clnt_cots_min_tout = CLNT_MIN_TIMEOUT; 479 9806 dai int clnt_cots_min_conntout = CLNT_MIN_CONNTIMEOUT; 480 0 stevel 481 0 stevel /* 482 0 stevel * Limit the number of times we will attempt to receive a reply without 483 0 stevel * re-sending a response. 484 0 stevel */ 485 0 stevel #define CLNT_MAXRECV_WITHOUT_RETRY 3 486 9806 dai uint_t clnt_cots_maxrecv = CLNT_MAXRECV_WITHOUT_RETRY; 487 0 stevel 488 0 stevel uint_t *clnt_max_msg_sizep; 489 0 stevel void (*clnt_stop_idle)(queue_t *wq); 490 0 stevel 491 0 stevel #define ptoh(p) (&((p)->cku_client)) 492 0 stevel #define htop(h) ((cku_private_t *)((h)->cl_private)) 493 0 stevel 494 0 stevel /* 495 0 stevel * Times to retry 496 0 stevel */ 497 0 stevel #define REFRESHES 2 /* authentication refreshes */ 498 0 stevel 499 681 rg137905 /* 500 681 rg137905 * The following is used to determine the global default behavior for 501 681 rg137905 * COTS when binding to a local port. 502 681 rg137905 * 503 681 rg137905 * If the value is set to 1 the default will be to select a reserved 504 681 rg137905 * (aka privileged) port, if the value is zero the default will be to 505 681 rg137905 * use non-reserved ports. Users of kRPC may override this by using 506 681 rg137905 * CLNT_CONTROL() and CLSET_BINDRESVPORT. 507 681 rg137905 */ 508 9806 dai int clnt_cots_do_bindresvport = 1; 509 0 stevel 510 0 stevel static zone_key_t zone_cots_key; 511 10004 dai 512 10004 dai /* 513 10004 dai * Defaults TCP send and receive buffer size for RPC connections. 514 10004 dai * These values can be tuned by /etc/system. 515 10004 dai */ 516 10004 dai int rpc_send_bufsz = 1024*1024; 517 10004 dai int rpc_recv_bufsz = 1024*1024; 518 10004 dai /* 519 10004 dai * To use system-wide default for TCP send and receive buffer size, 520 10004 dai * use /etc/system to set rpc_default_tcp_bufsz to 1: 521 10004 dai * 522 10004 dai * set rpcmod:rpc_default_tcp_bufsz=1 523 10004 dai */ 524 10004 dai int rpc_default_tcp_bufsz = 0; 525 0 stevel 526 0 stevel /* 527 0 stevel * We need to do this after all kernel threads in the zone have exited. 528 0 stevel */ 529 0 stevel /* ARGSUSED */ 530 0 stevel static void 531 0 stevel clnt_zone_destroy(zoneid_t zoneid, void *unused) 532 0 stevel { 533 0 stevel struct cm_xprt **cmp; 534 0 stevel struct cm_xprt *cm_entry; 535 0 stevel struct cm_xprt *freelist = NULL; 536 0 stevel 537 0 stevel mutex_enter(&connmgr_lock); 538 0 stevel cmp = &cm_hd; 539 0 stevel while ((cm_entry = *cmp) != NULL) { 540 0 stevel if (cm_entry->x_zoneid == zoneid) { 541 0 stevel *cmp = cm_entry->x_next; 542 0 stevel cm_entry->x_next = freelist; 543 0 stevel freelist = cm_entry; 544 0 stevel } else { 545 0 stevel cmp = &cm_entry->x_next; 546 0 stevel } 547 0 stevel } 548 0 stevel mutex_exit(&connmgr_lock); 549 0 stevel while ((cm_entry = freelist) != NULL) { 550 0 stevel freelist = cm_entry->x_next; 551 0 stevel connmgr_close(cm_entry); 552 0 stevel } 553 0 stevel } 554 0 stevel 555 0 stevel int 556 0 stevel clnt_cots_kcreate(dev_t dev, struct netbuf *addr, int family, rpcprog_t prog, 557 0 stevel rpcvers_t vers, uint_t max_msgsize, cred_t *cred, CLIENT **ncl) 558 0 stevel { 559 0 stevel CLIENT *h; 560 0 stevel cku_private_t *p; 561 0 stevel struct rpc_msg call_msg; 562 0 stevel struct rpcstat *rpcstat; 563 0 stevel 564 0 stevel RPCLOG(8, "clnt_cots_kcreate: prog %u\n", prog); 565 0 stevel 566 766 carlsonj rpcstat = zone_getspecific(rpcstat_zone_key, rpc_zone()); 567 0 stevel ASSERT(rpcstat != NULL); 568 0 stevel 569 0 stevel /* Allocate and intialize the client handle. */ 570 0 stevel p = kmem_zalloc(sizeof (*p), KM_SLEEP); 571 0 stevel 572 0 stevel h = ptoh(p); 573 0 stevel 574 0 stevel h->cl_private = (caddr_t)p; 575 0 stevel h->cl_auth = authkern_create(); 576 0 stevel h->cl_ops = &tcp_ops; 577 0 stevel 578 0 stevel cv_init(&p->cku_call.call_cv, NULL, CV_DEFAULT, NULL); 579 0 stevel mutex_init(&p->cku_call.call_lock, NULL, MUTEX_DEFAULT, NULL); 580 0 stevel 581 0 stevel /* 582 0 stevel * If the current sanity check size in rpcmod is smaller 583 0 stevel * than the size needed, then increase the sanity check. 584 0 stevel */ 585 0 stevel if (max_msgsize != 0 && clnt_max_msg_sizep != NULL && 586 0 stevel max_msgsize > *clnt_max_msg_sizep) { 587 0 stevel mutex_enter(&clnt_max_msg_lock); 588 0 stevel if (max_msgsize > *clnt_max_msg_sizep) 589 0 stevel *clnt_max_msg_sizep = max_msgsize; 590 0 stevel mutex_exit(&clnt_max_msg_lock); 591 0 stevel } 592 0 stevel 593 0 stevel p->cku_outbuflen = COTS_DEFAULT_ALLOCSIZE; 594 0 stevel 595 0 stevel /* Preserialize the call message header */ 596 0 stevel 597 0 stevel call_msg.rm_xid = 0; 598 0 stevel call_msg.rm_direction = CALL; 599 0 stevel call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 600 0 stevel call_msg.rm_call.cb_prog = prog; 601 0 stevel call_msg.rm_call.cb_vers = vers; 602 0 stevel 603 0 stevel xdrmem_create(&p->cku_outxdr, p->cku_rpchdr, WIRE_HDR_SIZE, XDR_ENCODE); 604 0 stevel 605 0 stevel if (!xdr_callhdr(&p->cku_outxdr, &call_msg)) { 606 0 stevel RPCLOG0(1, "clnt_cots_kcreate - Fatal header serialization " 607 0 stevel "error\n"); 608 0 stevel auth_destroy(h->cl_auth); 609 0 stevel kmem_free(p, sizeof (cku_private_t)); 610 0 stevel RPCLOG0(1, "clnt_cots_kcreate: create failed error EINVAL\n"); 611 0 stevel return (EINVAL); /* XXX */ 612 0 stevel } 613 0 stevel 614 0 stevel /* 615 0 stevel * The zalloc initialized the fields below. 616 0 stevel * p->cku_xid = 0; 617 0 stevel * p->cku_flags = 0; 618 0 stevel * p->cku_srcaddr.len = 0; 619 0 stevel * p->cku_srcaddr.maxlen = 0; 620 0 stevel */ 621 0 stevel 622 0 stevel p->cku_cred = cred; 623 0 stevel p->cku_device = dev; 624 0 stevel p->cku_addrfmly = family; 625 0 stevel p->cku_addr.buf = kmem_zalloc(addr->maxlen, KM_SLEEP); 626 0 stevel p->cku_addr.maxlen = addr->maxlen; 627 0 stevel p->cku_addr.len = addr->len; 628 0 stevel bcopy(addr->buf, p->cku_addr.buf, addr->len); 629 0 stevel p->cku_stats = rpcstat->rpc_cots_client; 630 0 stevel p->cku_useresvport = -1; /* value is has not been set */ 631 0 stevel 632 0 stevel *ncl = h; 633 0 stevel return (0); 634 0 stevel } 635 0 stevel 636 0 stevel /*ARGSUSED*/ 637 0 stevel static void 638 0 stevel clnt_cots_kabort(CLIENT *h) 639 0 stevel { 640 0 stevel } 641 0 stevel 642 0 stevel /* 643 0 stevel * Return error info on this handle. 644 0 stevel */ 645 0 stevel static void 646 0 stevel clnt_cots_kerror(CLIENT *h, struct rpc_err *err) 647 0 stevel { 648 0 stevel /* LINTED pointer alignment */ 649 0 stevel cku_private_t *p = htop(h); 650 0 stevel 651 0 stevel *err = p->cku_err; 652 0 stevel } 653 0 stevel 654 0 stevel static bool_t 655 0 stevel clnt_cots_kfreeres(CLIENT *h, xdrproc_t xdr_res, caddr_t res_ptr) 656 0 stevel { 657 0 stevel /* LINTED pointer alignment */ 658 0 stevel cku_private_t *p = htop(h); 659 0 stevel XDR *xdrs; 660 0 stevel 661 0 stevel xdrs = &(p->cku_outxdr); 662 0 stevel xdrs->x_op = XDR_FREE; 663 0 stevel return ((*xdr_res)(xdrs, res_ptr)); 664 0 stevel } 665 0 stevel 666 0 stevel static bool_t 667 0 stevel clnt_cots_kcontrol(CLIENT *h, int cmd, char *arg) 668 0 stevel { 669 0 stevel cku_private_t *p = htop(h); 670 0 stevel 671 0 stevel switch (cmd) { 672 0 stevel case CLSET_PROGRESS: 673 0 stevel p->cku_progress = TRUE; 674 0 stevel return (TRUE); 675 0 stevel 676 0 stevel case CLSET_XID: 677 0 stevel if (arg == NULL) 678 0 stevel return (FALSE); 679 0 stevel 680 0 stevel p->cku_xid = *((uint32_t *)arg); 681 0 stevel return (TRUE); 682 0 stevel 683 0 stevel case CLGET_XID: 684 0 stevel if (arg == NULL) 685 0 stevel return (FALSE); 686 0 stevel 687 0 stevel *((uint32_t *)arg) = p->cku_xid; 688 0 stevel return (TRUE); 689 0 stevel 690 0 stevel case CLSET_NODELAYONERR: 691 0 stevel if (arg == NULL) 692 0 stevel return (FALSE); 693 0 stevel 694 0 stevel if (*((bool_t *)arg) == TRUE) { 695 0 stevel p->cku_nodelayonerr = TRUE; 696 0 stevel return (TRUE); 697 0 stevel } 698 0 stevel if (*((bool_t *)arg) == FALSE) { 699 0 stevel p->cku_nodelayonerr = FALSE; 700 0 stevel return (TRUE); 701 0 stevel } 702 0 stevel return (FALSE); 703 0 stevel 704 0 stevel case CLGET_NODELAYONERR: 705 0 stevel if (arg == NULL) 706 0 stevel return (FALSE); 707 0 stevel 708 0 stevel *((bool_t *)arg) = p->cku_nodelayonerr; 709 0 stevel return (TRUE); 710 0 stevel 711 0 stevel case CLSET_BINDRESVPORT: 712 0 stevel if (arg == NULL) 713 0 stevel return (FALSE); 714 0 stevel 715 0 stevel if (*(int *)arg != 1 && *(int *)arg != 0) 716 0 stevel return (FALSE); 717 0 stevel 718 0 stevel p->cku_useresvport = *(int *)arg; 719 0 stevel 720 0 stevel return (TRUE); 721 0 stevel 722 0 stevel case CLGET_BINDRESVPORT: 723 0 stevel if (arg == NULL) 724 0 stevel return (FALSE); 725 0 stevel 726 0 stevel *(int *)arg = p->cku_useresvport; 727 0 stevel 728 0 stevel return (TRUE); 729 0 stevel 730 0 stevel default: 731 0 stevel return (FALSE); 732 0 stevel } 733 0 stevel } 734 0 stevel 735 0 stevel /* 736 0 stevel * Destroy rpc handle. Frees the space used for output buffer, 737 0 stevel * private data, and handle structure. 738 0 stevel */ 739 0 stevel static void 740 0 stevel clnt_cots_kdestroy(CLIENT *h) 741 0 stevel { 742 0 stevel /* LINTED pointer alignment */ 743 0 stevel cku_private_t *p = htop(h); 744 0 stevel calllist_t *call = &p->cku_call; 745 0 stevel 746 0 stevel RPCLOG(8, "clnt_cots_kdestroy h: %p\n", (void *)h); 747 0 stevel RPCLOG(8, "clnt_cots_kdestroy h: xid=0x%x\n", p->cku_xid); 748 0 stevel 749 0 stevel if (p->cku_flags & CKU_ONQUEUE) { 750 0 stevel RPCLOG(64, "clnt_cots_kdestroy h: removing call for xid 0x%x " 751 0 stevel "from dispatch list\n", p->cku_xid); 752 0 stevel call_table_remove(call); 753 0 stevel } 754 0 stevel 755 0 stevel if (call->call_reply) 756 0 stevel freemsg(call->call_reply); 757 0 stevel cv_destroy(&call->call_cv); 758 0 stevel mutex_destroy(&call->call_lock); 759 0 stevel 760 0 stevel kmem_free(p->cku_srcaddr.buf, p->cku_srcaddr.maxlen); 761 0 stevel kmem_free(p->cku_addr.buf, p->cku_addr.maxlen); 762 0 stevel kmem_free(p, sizeof (*p)); 763 0 stevel } 764 0 stevel 765 0 stevel static int clnt_cots_pulls; 766 0 stevel #define RM_HDR_SIZE 4 /* record mark header size */ 767 0 stevel 768 0 stevel /* 769 0 stevel * Call remote procedure. 770 0 stevel */ 771 0 stevel static enum clnt_stat 772 0 stevel clnt_cots_kcallit(CLIENT *h, rpcproc_t procnum, xdrproc_t xdr_args, 773 0 stevel caddr_t argsp, xdrproc_t xdr_results, caddr_t resultsp, struct timeval wait) 774 0 stevel { 775 0 stevel /* LINTED pointer alignment */ 776 0 stevel cku_private_t *p = htop(h); 777 0 stevel calllist_t *call = &p->cku_call; 778 0 stevel XDR *xdrs; 779 0 stevel struct rpc_msg reply_msg; 780 0 stevel mblk_t *mp; 781 0 stevel #ifdef RPCDEBUG 782 0 stevel clock_t time_sent; 783 0 stevel #endif 784 0 stevel struct netbuf *retryaddr; 785 0 stevel struct cm_xprt *cm_entry = NULL; 786 0 stevel queue_t *wq; 787 9675 dai int len, waitsecs, max_waitsecs; 788 0 stevel int mpsize; 789 0 stevel int refreshes = REFRESHES; 790 0 stevel int interrupted; 791 0 stevel int tidu_size; 792 0 stevel enum clnt_stat status; 793 0 stevel struct timeval cwait; 794 0 stevel bool_t delay_first = FALSE; 795 11066 rafael clock_t ticks, now; 796 0 stevel 797 0 stevel RPCLOG(2, "clnt_cots_kcallit, procnum %u\n", procnum); 798 0 stevel COTSRCSTAT_INCR(p->cku_stats, rccalls); 799 0 stevel 800 0 stevel RPCLOG(2, "clnt_cots_kcallit: wait.tv_sec: %ld\n", wait.tv_sec); 801 0 stevel RPCLOG(2, "clnt_cots_kcallit: wait.tv_usec: %ld\n", wait.tv_usec); 802 0 stevel /* 803 0 stevel * Bug ID 1240234: 804 0 stevel * Look out for zero length timeouts. We don't want to 805 0 stevel * wait zero seconds for a connection to be established. 806 0 stevel */ 807 0 stevel if (wait.tv_sec < clnt_cots_min_conntout) { 808 0 stevel cwait.tv_sec = clnt_cots_min_conntout; 809 0 stevel cwait.tv_usec = 0; 810 0 stevel RPCLOG(8, "clnt_cots_kcallit: wait.tv_sec (%ld) too low,", 811 0 stevel wait.tv_sec); 812 0 stevel RPCLOG(8, " setting to: %d\n", clnt_cots_min_conntout); 813 0 stevel } else { 814 0 stevel cwait = wait; 815 0 stevel } 816 0 stevel 817 0 stevel call_again: 818 0 stevel if (cm_entry) { 819 0 stevel connmgr_release(cm_entry); 820 0 stevel cm_entry = NULL; 821 0 stevel } 822 0 stevel 823 0 stevel mp = NULL; 824 0 stevel 825 0 stevel /* 826 0 stevel * If the call is not a retry, allocate a new xid and cache it 827 0 stevel * for future retries. 828 0 stevel * Bug ID 1246045: 829 0 stevel * Treat call as a retry for purposes of binding the source 830 0 stevel * port only if we actually attempted to send anything on 831 0 stevel * the previous call. 832 0 stevel */ 833 0 stevel if (p->cku_xid == 0) { 834 0 stevel p->cku_xid = alloc_xid(); 835 6403 gt29601 call->call_zoneid = rpc_zoneid(); 836 6403 gt29601 837 0 stevel /* 838 0 stevel * We need to ASSERT here that our xid != 0 because this 839 0 stevel * determines whether or not our call record gets placed on 840 0 stevel * the hash table or the linked list. By design, we mandate 841 0 stevel * that RPC calls over cots must have xid's != 0, so we can 842 0 stevel * ensure proper management of the hash table. 843 0 stevel */ 844 0 stevel ASSERT(p->cku_xid != 0); 845 0 stevel 846 0 stevel retryaddr = NULL; 847 0 stevel p->cku_flags &= ~CKU_SENT; 848 0 stevel 849 0 stevel if (p->cku_flags & CKU_ONQUEUE) { 850 0 stevel RPCLOG(8, "clnt_cots_kcallit: new call, dequeuing old" 851 0 stevel " one (%p)\n", (void *)call); 852 0 stevel call_table_remove(call); 853 0 stevel p->cku_flags &= ~CKU_ONQUEUE; 854 0 stevel RPCLOG(64, "clnt_cots_kcallit: removing call from " 855 0 stevel "dispatch list because xid was zero (now 0x%x)\n", 856 0 stevel p->cku_xid); 857 0 stevel } 858 0 stevel 859 0 stevel if (call->call_reply != NULL) { 860 0 stevel freemsg(call->call_reply); 861 0 stevel call->call_reply = NULL; 862 0 stevel } 863 0 stevel } else if (p->cku_srcaddr.buf == NULL || p->cku_srcaddr.len == 0) { 864 0 stevel retryaddr = NULL; 865 0 stevel 866 0 stevel } else if (p->cku_flags & CKU_SENT) { 867 0 stevel retryaddr = &p->cku_srcaddr; 868 0 stevel 869 0 stevel } else { 870 0 stevel /* 871 0 stevel * Bug ID 1246045: Nothing was sent, so set retryaddr to 872 0 stevel * NULL and let connmgr_get() bind to any source port it 873 0 stevel * can get. 874 0 stevel */ 875 0 stevel retryaddr = NULL; 876 0 stevel } 877 0 stevel 878 0 stevel RPCLOG(64, "clnt_cots_kcallit: xid = 0x%x", p->cku_xid); 879 0 stevel RPCLOG(64, " flags = 0x%x\n", p->cku_flags); 880 0 stevel 881 0 stevel p->cku_err.re_status = RPC_TIMEDOUT; 882 0 stevel p->cku_err.re_errno = p->cku_err.re_terrno = 0; 883 0 stevel 884 0 stevel cm_entry = connmgr_wrapget(retryaddr, &cwait, p); 885 0 stevel 886 0 stevel if (cm_entry == NULL) { 887 0 stevel RPCLOG(1, "clnt_cots_kcallit: can't connect status %s\n", 888 0 stevel clnt_sperrno(p->cku_err.re_status)); 889 0 stevel 890 0 stevel /* 891 0 stevel * The reasons why we fail to create a connection are 892 0 stevel * varied. In most cases we don't want the caller to 893 0 stevel * immediately retry. This could have one or more 894 0 stevel * bad effects. This includes flooding the net with 895 0 stevel * connect requests to ports with no listener; a hard 896 0 stevel * kernel loop due to all the "reserved" TCP ports being 897 0 stevel * in use. 898 0 stevel */ 899 0 stevel delay_first = TRUE; 900 0 stevel 901 0 stevel /* 902 0 stevel * Even if we end up returning EINTR, we still count a 903 0 stevel * a "can't connect", because the connection manager 904 0 stevel * might have been committed to waiting for or timing out on 905 0 stevel * a connection. 906 0 stevel */ 907 0 stevel COTSRCSTAT_INCR(p->cku_stats, rccantconn); 908 0 stevel switch (p->cku_err.re_status) { 909 0 stevel case RPC_INTR: 910 0 stevel p->cku_err.re_errno = EINTR; 911 0 stevel 912 0 stevel /* 913 0 stevel * No need to delay because a UNIX signal(2) 914 0 stevel * interrupted us. The caller likely won't 915 0 stevel * retry the CLNT_CALL() and even if it does, 916 0 stevel * we assume the caller knows what it is doing. 917 0 stevel */ 918 0 stevel delay_first = FALSE; 919 0 stevel break; 920 0 stevel 921 0 stevel case RPC_TIMEDOUT: 922 0 stevel p->cku_err.re_errno = ETIMEDOUT; 923 0 stevel 924 0 stevel /* 925 0 stevel * No need to delay because timed out already 926 0 stevel * on the connection request and assume that the 927 0 stevel * transport time out is longer than our minimum 928 0 stevel * timeout, or least not too much smaller. 929 0 stevel */ 930 0 stevel delay_first = FALSE; 931 0 stevel break; 932 0 stevel 933 0 stevel case RPC_SYSTEMERROR: 934 0 stevel case RPC_TLIERROR: 935 0 stevel /* 936 0 stevel * We want to delay here because a transient 937 0 stevel * system error has a better chance of going away 938 0 stevel * if we delay a bit. If it's not transient, then 939 0 stevel * we don't want end up in a hard kernel loop 940 0 stevel * due to retries. 941 0 stevel */ 942 0 stevel ASSERT(p->cku_err.re_errno != 0); 943 0 stevel break; 944 0 stevel 945 0 stevel 946 0 stevel case RPC_CANTCONNECT: 947 0 stevel /* 948 0 stevel * RPC_CANTCONNECT is set on T_ERROR_ACK which 949 0 stevel * implies some error down in the TCP layer or 950 0 stevel * below. If cku_nodelayonerror is set then we 951 0 stevel * assume the caller knows not to try too hard. 952 0 stevel */ 953 0 stevel RPCLOG0(8, "clnt_cots_kcallit: connection failed,"); 954 0 stevel RPCLOG0(8, " re_status=RPC_CANTCONNECT,"); 955 0 stevel RPCLOG(8, " re_errno=%d,", p->cku_err.re_errno); 956 0 stevel RPCLOG(8, " cku_nodelayonerr=%d", p->cku_nodelayonerr); 957 0 stevel if (p->cku_nodelayonerr == TRUE) 958 0 stevel delay_first = FALSE; 959 0 stevel 960 0 stevel p->cku_err.re_errno = EIO; 961 0 stevel 962 0 stevel break; 963 0 stevel 964 0 stevel case RPC_XPRTFAILED: 965 0 stevel /* 966 0 stevel * We want to delay here because we likely 967 0 stevel * got a refused connection. 968 0 stevel */ 969 4457 vv149972 if (p->cku_err.re_errno == 0) 970 4457 vv149972 p->cku_err.re_errno = EIO; 971 0 stevel 972 4457 vv149972 RPCLOG(1, "clnt_cots_kcallit: transport failed: %d\n", 973 4457 vv149972 p->cku_err.re_errno); 974 4457 vv149972 975 4457 vv149972 break; 976 0 stevel 977 0 stevel default: 978 0 stevel /* 979 0 stevel * We delay here because it is better to err 980 0 stevel * on the side of caution. If we got here then 981 0 stevel * status could have been RPC_SUCCESS, but we 982 0 stevel * know that we did not get a connection, so 983 0 stevel * force the rpc status to RPC_CANTCONNECT. 984 0 stevel */ 985 0 stevel p->cku_err.re_status = RPC_CANTCONNECT; 986 0 stevel p->cku_err.re_errno = EIO; 987 0 stevel break; 988 0 stevel } 989 0 stevel if (delay_first == TRUE) 990 0 stevel ticks = clnt_cots_min_tout * drv_usectohz(1000000); 991 0 stevel goto cots_done; 992 0 stevel } 993 0 stevel 994 0 stevel /* 995 0 stevel * If we've never sent any request on this connection (send count 996 0 stevel * is zero, or the connection has been reset), cache the 997 0 stevel * the connection's create time and send a request (possibly a retry) 998 0 stevel */ 999 0 stevel if ((p->cku_flags & CKU_SENT) == 0 || 1000 0 stevel p->cku_ctime != cm_entry->x_ctime) { 1001 0 stevel p->cku_ctime = cm_entry->x_ctime; 1002 0 stevel 1003 0 stevel } else if ((p->cku_flags & CKU_SENT) && (p->cku_flags & CKU_ONQUEUE) && 1004 0 stevel (call->call_reply != NULL || 1005 0 stevel p->cku_recv_attempts < clnt_cots_maxrecv)) { 1006 0 stevel 1007 0 stevel /* 1008 0 stevel * If we've sent a request and our call is on the dispatch 1009 0 stevel * queue and we haven't made too many receive attempts, then 1010 0 stevel * don't re-send, just receive. 1011 0 stevel */ 1012 0 stevel p->cku_recv_attempts++; 1013 0 stevel goto read_again; 1014 0 stevel } 1015 0 stevel 1016 0 stevel /* 1017 0 stevel * Now we create the RPC request in a STREAMS message. We have to do 1018 0 stevel * this after the call to connmgr_get so that we have the correct 1019 0 stevel * TIDU size for the transport. 1020 0 stevel */ 1021 0 stevel tidu_size = cm_entry->x_tidu_size; 1022 0 stevel len = MSG_OFFSET + MAX(tidu_size, RM_HDR_SIZE + WIRE_HDR_SIZE); 1023 0 stevel 1024 0 stevel while ((mp = allocb(len, BPRI_MED)) == NULL) { 1025 0 stevel if (strwaitbuf(len, BPRI_MED)) { 1026 0 stevel p->cku_err.re_status = RPC_SYSTEMERROR; 1027 0 stevel p->cku_err.re_errno = ENOSR; 1028 0 stevel COTSRCSTAT_INCR(p->cku_stats, rcnomem); 1029 0 stevel goto cots_done; 1030 0 stevel } 1031 0 stevel } 1032 0 stevel xdrs = &p->cku_outxdr; 1033 0 stevel xdrmblk_init(xdrs, mp, XDR_ENCODE, tidu_size); 1034 0 stevel mpsize = MBLKSIZE(mp); 1035 0 stevel ASSERT(mpsize >= len); 1036 0 stevel ASSERT(mp->b_rptr == mp->b_datap->db_base); 1037 0 stevel 1038 0 stevel /* 1039 0 stevel * If the size of mblk is not appreciably larger than what we 1040 0 stevel * asked, then resize the mblk to exactly len bytes. The reason for 1041 0 stevel * this: suppose len is 1600 bytes, the tidu is 1460 bytes 1042 0 stevel * (from TCP over ethernet), and the arguments to the RPC require 1043 0 stevel * 2800 bytes. Ideally we want the protocol to render two 1044 0 stevel * ~1400 byte segments over the wire. However if allocb() gives us a 2k 1045 0 stevel * mblk, and we allocate a second mblk for the remainder, the protocol 1046 0 stevel * module may generate 3 segments over the wire: 1047 0 stevel * 1460 bytes for the first, 448 (2048 - 1600) for the second, and 1048 0 stevel * 892 for the third. If we "waste" 448 bytes in the first mblk, 1049 0 stevel * the XDR encoding will generate two ~1400 byte mblks, and the 1050 0 stevel * protocol module is more likely to produce properly sized segments. 1051 0 stevel */ 1052 0 stevel if ((mpsize >> 1) <= len) 1053 0 stevel mp->b_rptr += (mpsize - len); 1054 0 stevel 1055 0 stevel /* 1056 0 stevel * Adjust b_rptr to reserve space for the non-data protocol headers 1057 0 stevel * any downstream modules might like to add, and for the 1058 0 stevel * record marking header. 1059 0 stevel */ 1060 0 stevel mp->b_rptr += (MSG_OFFSET + RM_HDR_SIZE); 1061 0 stevel 1062 0 stevel if (h->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { 1063 0 stevel /* Copy in the preserialized RPC header information. */ 1064 0 stevel bcopy(p->cku_rpchdr, mp->b_rptr, WIRE_HDR_SIZE); 1065 0 stevel 1066 0 stevel /* Use XDR_SETPOS() to set the b_wptr to past the RPC header. */ 1067 0 stevel XDR_SETPOS(xdrs, (uint_t)(mp->b_rptr - mp->b_datap->db_base + 1068 0 stevel WIRE_HDR_SIZE)); 1069 0 stevel 1070 0 stevel ASSERT((mp->b_wptr - mp->b_rptr) == WIRE_HDR_SIZE); 1071 0 stevel 1072 0 stevel /* Serialize the procedure number and the arguments. */ 1073 0 stevel if ((!XDR_PUTINT32(xdrs, (int32_t *)&procnum)) || 1074 0 stevel (!AUTH_MARSHALL(h->cl_auth, xdrs, p->cku_cred)) || 1075 0 stevel (!(*xdr_args)(xdrs, argsp))) { 1076 0 stevel p->cku_err.re_status = RPC_CANTENCODEARGS; 1077 0 stevel p->cku_err.re_errno = EIO; 1078 0 stevel goto cots_done; 1079 0 stevel } 1080 0 stevel 1081 0 stevel (*(uint32_t *)(mp->b_rptr)) = p->cku_xid; 1082 0 stevel } else { 1083 0 stevel uint32_t *uproc = (uint32_t *)&p->cku_rpchdr[WIRE_HDR_SIZE]; 1084 0 stevel IXDR_PUT_U_INT32(uproc, procnum); 1085 0 stevel 1086 0 stevel (*(uint32_t *)(&p->cku_rpchdr[0])) = p->cku_xid; 1087 0 stevel 1088 0 stevel /* Use XDR_SETPOS() to set the b_wptr. */ 1089 0 stevel XDR_SETPOS(xdrs, (uint_t)(mp->b_rptr - mp->b_datap->db_base)); 1090 0 stevel 1091 0 stevel /* Serialize the procedure number and the arguments. */ 1092 0 stevel if (!AUTH_WRAP(h->cl_auth, p->cku_rpchdr, WIRE_HDR_SIZE+4, 1093 0 stevel xdrs, xdr_args, argsp)) { 1094 0 stevel p->cku_err.re_status = RPC_CANTENCODEARGS; 1095 0 stevel p->cku_err.re_errno = EIO; 1096 0 stevel goto cots_done; 1097 0 stevel } 1098 0 stevel } 1099 0 stevel 1100 0 stevel RPCLOG(2, "clnt_cots_kcallit: connected, sending call, tidu_size %d\n", 1101 0 stevel tidu_size); 1102 0 stevel 1103 0 stevel wq = cm_entry->x_wq; 1104 9675 dai waitsecs = 0; 1105 9675 dai 1106 9675 dai dispatch_again: 1107 8205 Siddheshwar status = clnt_dispatch_send(wq, mp, call, p->cku_xid, 1108 6403 gt29601 (p->cku_flags & CKU_ONQUEUE)); 1109 8205 Siddheshwar 1110 9675 dai if ((status == RPC_CANTSEND) && (call->call_reason == ENOBUFS)) { 1111 9675 dai /* 1112 9675 dai * QFULL condition, allow some time for queue to drain 1113 9675 dai * and try again. Give up after waiting for all timeout 1114 9675 dai * specified for the call, or zone is going away. 1115 9675 dai */ 1116 9675 dai max_waitsecs = wait.tv_sec ? wait.tv_sec : clnt_cots_min_tout; 1117 9675 dai if ((waitsecs++ < max_waitsecs) && 1118 9675 dai !(zone_status_get(curproc->p_zone) >= 1119 9675 dai ZONE_IS_SHUTTING_DOWN)) { 1120 9675 dai 1121 9675 dai /* wait 1 sec for queue to drain */ 1122 9675 dai if (clnt_delay(drv_usectohz(1000000), 1123 9675 dai h->cl_nosignal) == EINTR) { 1124 9675 dai p->cku_err.re_errno = EINTR; 1125 9675 dai p->cku_err.re_status = RPC_INTR; 1126 9675 dai 1127 9675 dai goto cots_done; 1128 9675 dai } 1129 9675 dai 1130 9675 dai /* and try again */ 1131 9675 dai goto dispatch_again; 1132 9675 dai } 1133 8205 Siddheshwar p->cku_err.re_status = status; 1134 9675 dai p->cku_err.re_errno = call->call_reason; 1135 8205 Siddheshwar DTRACE_PROBE(krpc__e__clntcots__kcallit__cantsend); 1136 8205 Siddheshwar 1137 9675 dai goto cots_done; 1138 9675 dai } 1139 8205 Siddheshwar 1140 9675 dai if (waitsecs) { 1141 9675 dai /* adjust timeout to account for time wait to send */ 1142 9675 dai wait.tv_sec -= waitsecs; 1143 9675 dai if (wait.tv_sec < 0) { 1144 9675 dai /* pick up reply on next retry */ 1145 9675 dai wait.tv_sec = 0; 1146 9675 dai } 1147 9675 dai DTRACE_PROBE2(clnt_cots__sendwait, CLIENT *, h, 1148 9675 dai int, waitsecs); 1149 8205 Siddheshwar } 1150 0 stevel 1151 0 stevel RPCLOG(64, "clnt_cots_kcallit: sent call for xid 0x%x\n", 1152 6403 gt29601 (uint_t)p->cku_xid); 1153 0 stevel p->cku_flags = (CKU_ONQUEUE|CKU_SENT); 1154 0 stevel p->cku_recv_attempts = 1; 1155 0 stevel 1156 0 stevel #ifdef RPCDEBUG 1157 11066 rafael time_sent = ddi_get_lbolt(); 1158 0 stevel #endif 1159 0 stevel 1160 0 stevel /* 1161 0 stevel * Wait for a reply or a timeout. If there is no error or timeout, 1162 0 stevel * (both indicated by call_status), call->call_reply will contain 1163 0 stevel * the RPC reply message. 1164 0 stevel */ 1165 0 stevel read_again: 1166 0 stevel mutex_enter(&call->call_lock); 1167 0 stevel interrupted = 0; 1168 0 stevel if (call->call_status == RPC_TIMEDOUT) { 1169 0 stevel /* 1170 0 stevel * Indicate that the lwp is not to be stopped while waiting 1171 0 stevel * for this network traffic. This is to avoid deadlock while 1172 0 stevel * debugging a process via /proc and also to avoid recursive 1173 0 stevel * mutex_enter()s due to NFS page faults while stopping 1174 0 stevel * (NFS holds locks when it calls here). 1175 0 stevel */ 1176 0 stevel clock_t cv_wait_ret; 1177 0 stevel clock_t timout; 1178 0 stevel clock_t oldlbolt; 1179 0 stevel 1180 0 stevel klwp_t *lwp = ttolwp(curthread); 1181 0 stevel 1182 0 stevel if (lwp != NULL) 1183 0 stevel lwp->lwp_nostop++; 1184 0 stevel 1185 11066 rafael oldlbolt = ddi_get_lbolt(); 1186 0 stevel timout = wait.tv_sec * drv_usectohz(1000000) + 1187 0 stevel drv_usectohz(wait.tv_usec) + oldlbolt; 1188 0 stevel /* 1189 0 stevel * Iterate until the call_status is changed to something 1190 0 stevel * other that RPC_TIMEDOUT, or if cv_timedwait_sig() returns 1191 0 stevel * something <=0 zero. The latter means that we timed 1192 0 stevel * out. 1193 0 stevel */ 1194 0 stevel if (h->cl_nosignal) 1195 0 stevel while ((cv_wait_ret = cv_timedwait(&call->call_cv, 1196 0 stevel &call->call_lock, timout)) > 0 && 1197 6403 gt29601 call->call_status == RPC_TIMEDOUT) 1198 6403 gt29601 ; 1199 0 stevel else 1200 0 stevel while ((cv_wait_ret = cv_timedwait_sig( 1201 0 stevel &call->call_cv, 1202 0 stevel &call->call_lock, timout)) > 0 && 1203 6403 gt29601 call->call_status == RPC_TIMEDOUT) 1204 6403 gt29601 ; 1205 0 stevel 1206 0 stevel switch (cv_wait_ret) { 1207 0 stevel case 0: 1208 0 stevel /* 1209 0 stevel * If we got out of the above loop with 1210 0 stevel * cv_timedwait_sig() returning 0, then we were 1211 0 stevel * interrupted regardless what call_status is. 1212 0 stevel */ 1213 0 stevel interrupted = 1; 1214 0 stevel break; 1215 0 stevel case -1: 1216 0 stevel /* cv_timedwait_sig() timed out */ 1217 0 stevel break; 1218 0 stevel default: 1219 0 stevel 1220 0 stevel /* 1221 0 stevel * We were cv_signaled(). If we didn't 1222 0 stevel * get a successful call_status and returned 1223 0 stevel * before time expired, delay up to clnt_cots_min_tout 1224 0 stevel * seconds so that the caller doesn't immediately 1225 0 stevel * try to call us again and thus force the 1226 0 stevel * same condition that got us here (such 1227 0 stevel * as a RPC_XPRTFAILED due to the server not 1228 0 stevel * listening on the end-point. 1229 0 stevel */ 1230 0 stevel if (call->call_status != RPC_SUCCESS) { 1231 0 stevel clock_t curlbolt; 1232 0 stevel clock_t diff; 1233 0 stevel 1234 0 stevel curlbolt = ddi_get_lbolt(); 1235 0 stevel ticks = clnt_cots_min_tout * 1236 0 stevel drv_usectohz(1000000); 1237 0 stevel diff = curlbolt - oldlbolt; 1238 0 stevel if (diff < ticks) { 1239 0 stevel delay_first = TRUE; 1240 0 stevel if (diff > 0) 1241 0 stevel ticks -= diff; 1242 0 stevel } 1243 0 stevel } 1244 0 stevel break; 1245 0 stevel } 1246 0 stevel 1247 0 stevel if (lwp != NULL) 1248 0 stevel lwp->lwp_nostop--; 1249 0 stevel } 1250 0 stevel /* 1251 0 stevel * Get the reply message, if any. This will be freed at the end 1252 0 stevel * whether or not an error occurred. 1253 0 stevel */ 1254 0 stevel mp = call->call_reply; 1255 0 stevel call->call_reply = NULL; 1256 0 stevel 1257 0 stevel /* 1258 0 stevel * call_err is the error info when the call is on dispatch queue. 1259 0 stevel * cku_err is the error info returned to the caller. 1260 0 stevel * Sync cku_err with call_err for local message processing. 1261 0 stevel */ 1262 0 stevel 1263 0 stevel status = call->call_status; 1264 0 stevel p->cku_err = call->call_err; 1265 0 stevel mutex_exit(&call->call_lock); 1266 0 stevel 1267 0 stevel if (status != RPC_SUCCESS) { 1268 0 stevel switch (status) { 1269 0 stevel case RPC_TIMEDOUT: 1270 11066 rafael now = ddi_get_lbolt(); 1271 0 stevel if (interrupted) { 1272 0 stevel COTSRCSTAT_INCR(p->cku_stats, rcintrs); 1273 0 stevel p->cku_err.re_status = RPC_INTR; 1274 0 stevel p->cku_err.re_errno = EINTR; 1275 0 stevel RPCLOG(1, "clnt_cots_kcallit: xid 0x%x", 1276 0 stevel p->cku_xid); 1277 11066 rafael RPCLOG(1, "signal interrupted at %ld", now); 1278 0 stevel RPCLOG(1, ", was sent at %ld\n", time_sent); 1279 0 stevel } else { 1280 0 stevel COTSRCSTAT_INCR(p->cku_stats, rctimeouts); 1281 0 stevel p->cku_err.re_errno = ETIMEDOUT; 1282 0 stevel RPCLOG(1, "clnt_cots_kcallit: timed out at %ld", 1283 11066 rafael now); 1284 0 stevel RPCLOG(1, ", was sent at %ld\n", time_sent); 1285 0 stevel } 1286 0 stevel break; 1287 0 stevel 1288 0 stevel case RPC_XPRTFAILED: 1289 0 stevel if (p->cku_err.re_errno == 0) 1290 0 stevel p->cku_err.re_errno = EIO; 1291 0 stevel 1292 0 stevel RPCLOG(1, "clnt_cots_kcallit: transport failed: %d\n", 1293 0 stevel p->cku_err.re_errno); 1294 0 stevel break; 1295 0 stevel 1296 0 stevel case RPC_SYSTEMERROR: 1297 0 stevel ASSERT(p->cku_err.re_errno); 1298 0 stevel RPCLOG(1, "clnt_cots_kcallit: system error: %d\n", 1299 0 stevel p->cku_err.re_errno); 1300 0 stevel break; 1301 0 stevel 1302 0 stevel default: 1303 0 stevel p->cku_err.re_status = RPC_SYSTEMERROR; 1304 0 stevel p->cku_err.re_errno = EIO; 1305 0 stevel RPCLOG(1, "clnt_cots_kcallit: error: %s\n", 1306 0 stevel clnt_sperrno(status)); 1307 0 stevel break; 1308 0 stevel } 1309 0 stevel if (p->cku_err.re_status != RPC_TIMEDOUT) { 1310 0 stevel 1311 0 stevel if (p->cku_flags & CKU_ONQUEUE) { 1312 0 stevel call_table_remove(call); 1313 0 stevel p->cku_flags &= ~CKU_ONQUEUE; 1314 0 stevel } 1315 0 stevel 1316 0 stevel RPCLOG(64, "clnt_cots_kcallit: non TIMEOUT so xid 0x%x " 1317 0 stevel "taken off dispatch list\n", p->cku_xid); 1318 0 stevel if (call->call_reply) { 1319 0 stevel freemsg(call->call_reply); 1320 0 stevel call->call_reply = NULL; 1321 0 stevel } 1322 0 stevel } else if (wait.tv_sec != 0) { 1323 0 stevel /* 1324 0 stevel * We've sent the request over TCP and so we have 1325 0 stevel * every reason to believe it will get 1326 0 stevel * delivered. In which case returning a timeout is not 1327 0 stevel * appropriate. 1328 0 stevel */ 1329 0 stevel if (p->cku_progress == TRUE && 1330 0 stevel p->cku_recv_attempts < clnt_cots_maxrecv) { 1331 0 stevel p->cku_err.re_status = RPC_INPROGRESS; 1332 0 stevel } 1333 0 stevel } 1334 0 stevel goto cots_done; 1335 0 stevel } 1336 0 stevel 1337 0 stevel xdrs = &p->cku_inxdr; 1338 0 stevel xdrmblk_init(xdrs, mp, XDR_DECODE, 0); 1339 0 stevel 1340 0 stevel reply_msg.rm_direction = REPLY; 1341 0 stevel reply_msg.rm_reply.rp_stat = MSG_ACCEPTED; 1342 0 stevel reply_msg.acpted_rply.ar_stat = SUCCESS; 1343 0 stevel 1344 0 stevel reply_msg.acpted_rply.ar_verf = _null_auth; 1345 0 stevel /* 1346 0 stevel * xdr_results will be done in AUTH_UNWRAP. 1347 0 stevel */ 1348 0 stevel reply_msg.acpted_rply.ar_results.where = NULL; 1349 0 stevel reply_msg.acpted_rply.ar_results.proc = xdr_void; 1350 0 stevel 1351 0 stevel if (xdr_replymsg(xdrs, &reply_msg)) { 1352 0 stevel enum clnt_stat re_status; 1353 0 stevel 1354 0 stevel _seterr_reply(&reply_msg, &p->cku_err); 1355 0 stevel 1356 0 stevel re_status = p->cku_err.re_status; 1357 0 stevel if (re_status == RPC_SUCCESS) { 1358 0 stevel /* 1359 0 stevel * Reply is good, check auth. 1360 0 stevel */ 1361 0 stevel if (!AUTH_VALIDATE(h->cl_auth, 1362 6403 gt29601 &reply_msg.acpted_rply.ar_verf)) { 1363 0 stevel COTSRCSTAT_INCR(p->cku_stats, rcbadverfs); 1364 0 stevel RPCLOG0(1, "clnt_cots_kcallit: validation " 1365 6403 gt29601 "failure\n"); 1366 0 stevel freemsg(mp); 1367 0 stevel (void) xdr_rpc_free_verifier(xdrs, &reply_msg); 1368 0 stevel mutex_enter(&call->call_lock); 1369 0 stevel if (call->call_reply == NULL) 1370 0 stevel call->call_status = RPC_TIMEDOUT; 1371 0 stevel mutex_exit(&call->call_lock); 1372 0 stevel goto read_again; 1373 0 stevel } else if (!AUTH_UNWRAP(h->cl_auth, xdrs, 1374 6403 gt29601 xdr_results, resultsp)) { 1375 0 stevel RPCLOG0(1, "clnt_cots_kcallit: validation " 1376 6403 gt29601 "failure (unwrap)\n"); 1377 0 stevel p->cku_err.re_status = RPC_CANTDECODERES; 1378 0 stevel p->cku_err.re_errno = EIO; 1379 0 stevel } 1380 0 stevel } else { 1381 0 stevel /* set errno in case we can't recover */ 1382 0 stevel if (re_status != RPC_VERSMISMATCH && 1383 0 stevel re_status != RPC_AUTHERROR && 1384 0 stevel re_status != RPC_PROGVERSMISMATCH) 1385 0 stevel p->cku_err.re_errno = EIO; 1386 0 stevel 1387 0 stevel if (re_status == RPC_AUTHERROR) { 1388 0 stevel /* 1389 589 rg137905 * Maybe our credential need to be refreshed 1390 0 stevel */ 1391 571 rg137905 if (cm_entry) { 1392 571 rg137905 /* 1393 571 rg137905 * There is the potential that the 1394 571 rg137905 * cm_entry has/will be marked dead, 1395 589 rg137905 * so drop the connection altogether, 1396 589 rg137905 * force REFRESH to establish new 1397 589 rg137905 * connection. 1398 571 rg137905 */ 1399 589 rg137905 connmgr_cancelconn(cm_entry); 1400 571 rg137905 cm_entry = NULL; 1401 0 stevel } 1402 0 stevel 1403 571 rg137905 if ((refreshes > 0) && 1404 571 rg137905 AUTH_REFRESH(h->cl_auth, &reply_msg, 1405 6403 gt29601 p->cku_cred)) { 1406 571 rg137905 refreshes--; 1407 571 rg137905 (void) xdr_rpc_free_verifier(xdrs, 1408 6403 gt29601 &reply_msg); 1409 571 rg137905 freemsg(mp); 1410 571 rg137905 mp = NULL; 1411 571 rg137905 1412 571 rg137905 if (p->cku_flags & CKU_ONQUEUE) { 1413 571 rg137905 call_table_remove(call); 1414 571 rg137905 p->cku_flags &= ~CKU_ONQUEUE; 1415 571 rg137905 } 1416 571 rg137905 1417 571 rg137905 RPCLOG(64, 1418 571 rg137905 "clnt_cots_kcallit: AUTH_ERROR, xid" 1419 571 rg137905 " 0x%x removed off dispatch list\n", 1420 571 rg137905 p->cku_xid); 1421 571 rg137905 if (call->call_reply) { 1422 571 rg137905 freemsg(call->call_reply); 1423 571 rg137905 call->call_reply = NULL; 1424 571 rg137905 } 1425 571 rg137905 1426 571 rg137905 COTSRCSTAT_INCR(p->cku_stats, 1427 6403 gt29601 rcbadcalls); 1428 571 rg137905 COTSRCSTAT_INCR(p->cku_stats, 1429 6403 gt29601 rcnewcreds); 1430 571 rg137905 goto call_again; 1431 589 rg137905 } 1432 589 rg137905 1433 0 stevel /* 1434 0 stevel * We have used the client handle to 1435 0 stevel * do an AUTH_REFRESH and the RPC status may 1436 0 stevel * be set to RPC_SUCCESS; Let's make sure to 1437 0 stevel * set it to RPC_AUTHERROR. 1438 0 stevel */ 1439 0 stevel p->cku_err.re_status = RPC_AUTHERROR; 1440 589 rg137905 1441 0 stevel /* 1442 0 stevel * Map recoverable and unrecoverable 1443 0 stevel * authentication errors to appropriate errno 1444 0 stevel */ 1445 0 stevel switch (p->cku_err.re_why) { 1446 342 nd150628 case AUTH_TOOWEAK: 1447 342 nd150628 /* 1448 571 rg137905 * This could be a failure where the 1449 571 rg137905 * server requires use of a reserved 1450 571 rg137905 * port, check and optionally set the 1451 571 rg137905 * client handle useresvport trying 1452 571 rg137905 * one more time. Next go round we 1453 571 rg137905 * fall out with the tooweak error. 1454 342 nd150628 */ 1455 342 nd150628 if (p->cku_useresvport != 1) { 1456 342 nd150628 p->cku_useresvport = 1; 1457 342 nd150628 p->cku_xid = 0; 1458 342 nd150628 (void) xdr_rpc_free_verifier 1459 6403 gt29601 (xdrs, &reply_msg); 1460 342 nd150628 freemsg(mp); 1461 342 nd150628 goto call_again; 1462 342 nd150628 } 1463 342 nd150628 /* FALLTHRU */ 1464 0 stevel case AUTH_BADCRED: 1465 0 stevel case AUTH_BADVERF: 1466 0 stevel case AUTH_INVALIDRESP: 1467 0 stevel case AUTH_FAILED: 1468 0 stevel case RPCSEC_GSS_NOCRED: 1469 0 stevel case RPCSEC_GSS_FAILED: 1470 0 stevel p->cku_err.re_errno = EACCES; 1471 0 stevel break; 1472 0 stevel case AUTH_REJECTEDCRED: 1473 0 stevel case AUTH_REJECTEDVERF: 1474 0 stevel default: p->cku_err.re_errno = EIO; 1475 0 stevel break; 1476 0 stevel } 1477 0 stevel RPCLOG(1, "clnt_cots_kcallit : authentication" 1478 0 stevel " failed with RPC_AUTHERROR of type %d\n", 1479 0 stevel (int)p->cku_err.re_why); 1480 0 stevel } 1481 0 stevel } 1482 0 stevel } else { 1483 0 stevel /* reply didn't decode properly. */ 1484 0 stevel p->cku_err.re_status = RPC_CANTDECODERES; 1485 0 stevel p->cku_err.re_errno = EIO; 1486 0 stevel RPCLOG0(1, "clnt_cots_kcallit: decode failure\n"); 1487 0 stevel } 1488 0 stevel 1489 0 stevel (void) xdr_rpc_free_verifier(xdrs, &reply_msg); 1490 0 stevel 1491 0 stevel if (p->cku_flags & CKU_ONQUEUE) { 1492 0 stevel call_table_remove(call); 1493 0 stevel p->cku_flags &= ~CKU_ONQUEUE; 1494 0 stevel } 1495 0 stevel 1496 0 stevel RPCLOG(64, "clnt_cots_kcallit: xid 0x%x taken off dispatch list", 1497 0 stevel p->cku_xid); 1498 0 stevel RPCLOG(64, " status is %s\n", clnt_sperrno(p->cku_err.re_status)); 1499 0 stevel cots_done: 1500 0 stevel if (cm_entry) 1501 0 stevel connmgr_release(cm_entry); 1502 0 stevel 1503 0 stevel if (mp != NULL) 1504 0 stevel freemsg(mp); 1505 0 stevel if ((p->cku_flags & CKU_ONQUEUE) == 0 && call->call_reply) { 1506 0 stevel freemsg(call->call_reply); 1507 0 stevel call->call_reply = NULL; 1508 0 stevel } 1509 0 stevel if (p->cku_err.re_status != RPC_SUCCESS) { 1510 0 stevel RPCLOG0(1, "clnt_cots_kcallit: tail-end failure\n"); 1511 0 stevel COTSRCSTAT_INCR(p->cku_stats, rcbadcalls); 1512 0 stevel } 1513 0 stevel 1514 0 stevel /* 1515 0 stevel * No point in delaying if the zone is going away. 1516 0 stevel */ 1517 0 stevel if (delay_first == TRUE && 1518 0 stevel !(zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN)) { 1519 0 stevel if (clnt_delay(ticks, h->cl_nosignal) == EINTR) { 1520 0 stevel p->cku_err.re_errno = EINTR; 1521 0 stevel p->cku_err.re_status = RPC_INTR; 1522 0 stevel } 1523 0 stevel } 1524 0 stevel return (p->cku_err.re_status); 1525 0 stevel } 1526 0 stevel 1527 0 stevel /* 1528 0 stevel * Kinit routine for cots. This sets up the correct operations in 1529 0 stevel * the client handle, as the handle may have previously been a clts 1530 0 stevel * handle, and clears the xid field so there is no way a new call 1531 0 stevel * could be mistaken for a retry. It also sets in the handle the 1532 0 stevel * information that is passed at create/kinit time but needed at 1533 0 stevel * call time, as cots creates the transport at call time - device, 1534 0 stevel * address of the server, protocol family. 1535 0 stevel */ 1536 0 stevel void 1537 0 stevel clnt_cots_kinit(CLIENT *h, dev_t dev, int family, struct netbuf *addr, 1538 0 stevel int max_msgsize, cred_t *cred) 1539 0 stevel { 1540 0 stevel /* LINTED pointer alignment */ 1541 0 stevel cku_private_t *p = htop(h); 1542 0 stevel calllist_t *call = &p->cku_call; 1543 0 stevel 1544 0 stevel h->cl_ops = &tcp_ops; 1545 0 stevel if (p->cku_flags & CKU_ONQUEUE) { 1546 0 stevel call_table_remove(call); 1547 0 stevel p->cku_flags &= ~CKU_ONQUEUE; 1548 0 stevel RPCLOG(64, "clnt_cots_kinit: removing call for xid 0x%x from" 1549 0 stevel " dispatch list\n", p->cku_xid); 1550 0 stevel } 1551 0 stevel 1552 0 stevel if (call->call_reply != NULL) { 1553 0 stevel freemsg(call->call_reply); 1554 0 stevel call->call_reply = NULL; 1555 0 stevel } 1556 0 stevel 1557 0 stevel call->call_bucket = NULL; 1558 0 stevel call->call_hash = 0; 1559 0 stevel 1560 0 stevel /* 1561 0 stevel * We don't clear cku_flags here, because clnt_cots_kcallit() 1562 0 stevel * takes care of handling the cku_flags reset. 1563 0 stevel */ 1564 0 stevel p->cku_xid = 0; 1565 0 stevel p->cku_device = dev; 1566 0 stevel p->cku_addrfmly = family; 1567 0 stevel p->cku_cred = cred; 1568 0 stevel 1569 0 stevel if (p->cku_addr.maxlen < addr->len) { 1570 0 stevel if (p->cku_addr.maxlen != 0 && p->cku_addr.buf != NULL) 1571 0 stevel kmem_free(p->cku_addr.buf, p->cku_addr.maxlen); 1572 0 stevel p->cku_addr.buf = kmem_zalloc(addr->maxlen, KM_SLEEP); 1573 0 stevel p->cku_addr.maxlen = addr->maxlen; 1574 0 stevel } 1575 0 stevel 1576 0 stevel p->cku_addr.len = addr->len; 1577 0 stevel bcopy(addr->buf, p->cku_addr.buf, addr->len); 1578 0 stevel 1579 0 stevel /* 1580 0 stevel * If the current sanity check size in rpcmod is smaller 1581 0 stevel * than the size needed, then increase the sanity check. 1582 0 stevel */ 1583 0 stevel if (max_msgsize != 0 && clnt_max_msg_sizep != NULL && 1584 0 stevel max_msgsize > *clnt_max_msg_sizep) { 1585 0 stevel mutex_enter(&clnt_max_msg_lock); 1586 0 stevel if (max_msgsize > *clnt_max_msg_sizep) 1587 0 stevel *clnt_max_msg_sizep = max_msgsize; 1588 0 stevel mutex_exit(&clnt_max_msg_lock); 1589 0 stevel } 1590 0 stevel } 1591 0 stevel 1592 0 stevel /* 1593 0 stevel * ksettimers is a no-op for cots, with the exception of setting the xid. 1594 0 stevel */ 1595 0 stevel /* ARGSUSED */ 1596 0 stevel static int 1597 0 stevel clnt_cots_ksettimers(CLIENT *h, struct rpc_timers *t, struct rpc_timers *all, 1598 0 stevel int minimum, void (*feedback)(int, int, caddr_t), caddr_t arg, 1599 0 stevel uint32_t xid) 1600 0 stevel { 1601 0 stevel /* LINTED pointer alignment */ 1602 0 stevel cku_private_t *p = htop(h); 1603 0 stevel 1604 0 stevel if (xid) 1605 0 stevel p->cku_xid = xid; 1606 0 stevel COTSRCSTAT_INCR(p->cku_stats, rctimers); 1607 0 stevel return (0); 1608 0 stevel } 1609 0 stevel 1610 0 stevel extern void rpc_poptimod(struct vnode *); 1611 0 stevel extern int kstr_push(struct vnode *, char *); 1612 0 stevel 1613 0 stevel int 1614 0 stevel conn_kstat_update(kstat_t *ksp, int rw) 1615 0 stevel { 1616 0 stevel struct cm_xprt *cm_entry; 1617 0 stevel struct cm_kstat_xprt *cm_ksp_data; 1618 0 stevel uchar_t *b; 1619 0 stevel char *fbuf; 1620 0 stevel 1621 0 stevel if (rw == KSTAT_WRITE) 1622 0 stevel return (EACCES); 1623 0 stevel if (ksp == NULL || ksp->ks_private == NULL) 1624 0 stevel return (EIO); 1625 0 stevel cm_entry = (struct cm_xprt *)ksp->ks_private; 1626 0 stevel cm_ksp_data = (struct cm_kstat_xprt *)ksp->ks_data; 1627 0 stevel 1628 0 stevel cm_ksp_data->x_wq.value.ui32 = (uint32_t)(uintptr_t)cm_entry->x_wq; 1629 0 stevel cm_ksp_data->x_family.value.ui32 = cm_entry->x_family; 1630 0 stevel cm_ksp_data->x_rdev.value.ui32 = (uint32_t)cm_entry->x_rdev; 1631 0 stevel cm_ksp_data->x_time.value.ui32 = cm_entry->x_time; 1632 0 stevel cm_ksp_data->x_ref.value.ui32 = cm_entry->x_ref; 1633 0 stevel cm_ksp_data->x_state.value.ui32 = cm_entry->x_state_flags; 1634 0 stevel 1635 0 stevel if (cm_entry->x_server.buf) { 1636 457 bmc fbuf = cm_ksp_data->x_server.value.str.addr.ptr; 1637 0 stevel if (cm_entry->x_family == AF_INET && 1638 0 stevel cm_entry->x_server.len == 1639 0 stevel sizeof (struct sockaddr_in)) { 1640 0 stevel struct sockaddr_in *sa; 1641 0 stevel sa = (struct sockaddr_in *) 1642 0 stevel cm_entry->x_server.buf; 1643 0 stevel b = (uchar_t *)&sa->sin_addr; 1644 0 stevel (void) sprintf(fbuf, 1645 0 stevel "%03d.%03d.%03d.%03d", b[0] & 0xFF, b[1] & 0xFF, 1646 0 stevel b[2] & 0xFF, b[3] & 0xFF); 1647 0 stevel cm_ksp_data->x_port.value.ui32 = 1648 0 stevel (uint32_t)sa->sin_port; 1649 0 stevel } else if (cm_entry->x_family == AF_INET6 && 1650 0 stevel cm_entry->x_server.len >= 1651 0 stevel sizeof (struct sockaddr_in6)) { 1652 0 stevel /* extract server IP address & port */ 1653 0 stevel struct sockaddr_in6 *sin6; 1654 0 stevel sin6 = (struct sockaddr_in6 *)cm_entry->x_server.buf; 1655 0 stevel (void) kinet_ntop6((uchar_t *)&sin6->sin6_addr, fbuf, 1656 0 stevel INET6_ADDRSTRLEN); 1657 0 stevel cm_ksp_data->x_port.value.ui32 = sin6->sin6_port; 1658 0 stevel } else { 1659 0 stevel struct sockaddr_in *sa; 1660 0 stevel 1661 0 stevel sa = (struct sockaddr_in *)cm_entry->x_server.buf; 1662 0 stevel b = (uchar_t *)&sa->sin_addr; 1663 0 stevel (void) sprintf(fbuf, 1664 0 stevel "%03d.%03d.%03d.%03d", b[0] & 0xFF, b[1] & 0xFF, 1665 0 stevel b[2] & 0xFF, b[3] & 0xFF); 1666 0 stevel } 1667 0 stevel KSTAT_NAMED_STR_BUFLEN(&cm_ksp_data->x_server) = 1668 6403 gt29601 strlen(fbuf) + 1; 1669 0 stevel } 1670 0 stevel 1671 0 stevel return (0); 1672 0 stevel } 1673 0 stevel 1674 0 stevel 1675 0 stevel /* 1676 0 stevel * We want a version of delay which is interruptible by a UNIX signal 1677 0 stevel * Return EINTR if an interrupt occured. 1678 0 stevel */ 1679 0 stevel static int 1680 0 stevel clnt_delay(clock_t ticks, bool_t nosignal) 1681 0 stevel { 1682 0 stevel if (nosignal == TRUE) { 1683 0 stevel delay(ticks); 1684 0 stevel return (0); 1685 0 stevel } 1686 0 stevel return (delay_sig(ticks)); 1687 0 stevel } 1688 0 stevel 1689 0 stevel /* 1690 0 stevel * Wait for a connection until a timeout, or until we are 1691 0 stevel * signalled that there has been a connection state change. 1692 0 stevel */ 1693 0 stevel static enum clnt_stat 1694 0 stevel connmgr_cwait(struct cm_xprt *cm_entry, const struct timeval *waitp, 1695 0 stevel bool_t nosignal) 1696 0 stevel { 1697 0 stevel bool_t interrupted; 1698 0 stevel clock_t timout, cv_stat; 1699 0 stevel enum clnt_stat clstat; 1700 0 stevel unsigned int old_state; 1701 0 stevel 1702 0 stevel ASSERT(MUTEX_HELD(&connmgr_lock)); 1703 0 stevel /* 1704 0 stevel * We wait for the transport connection to be made, or an 1705 0 stevel * indication that it could not be made. 1706 0 stevel */ 1707 0 stevel clstat = RPC_TIMEDOUT; 1708 0 stevel interrupted = FALSE; 1709 0 stevel 1710 0 stevel old_state = cm_entry->x_state_flags; 1711 0 stevel /* 1712 0 stevel * Now loop until cv_timedwait{_sig} returns because of 1713 0 stevel * a signal(0) or timeout(-1) or cv_signal(>0). But it may be 1714 0 stevel * cv_signalled for various other reasons too. So loop 1715 0 stevel * until there is a state change on the connection. 1716 0 stevel */ 1717 0 stevel 1718 0 stevel timout = waitp->tv_sec * drv_usectohz(1000000) + 1719 11066 rafael drv_usectohz(waitp->tv_usec) + ddi_get_lbolt(); 1720 0 stevel 1721 0 stevel if (nosignal) { 1722 0 stevel while ((cv_stat = cv_timedwait(&cm_entry->x_conn_cv, 1723 0 stevel &connmgr_lock, timout)) > 0 && 1724 0 stevel cm_entry->x_state_flags == old_state) 1725 0 stevel ; 1726 0 stevel } else { 1727 0 stevel while ((cv_stat = cv_timedwait_sig(&cm_entry->x_conn_cv, 1728 0 stevel &connmgr_lock, timout)) > 0 && 1729 0 stevel cm_entry->x_state_flags == old_state) 1730 0 stevel ; 1731 0 stevel 1732 0 stevel if (cv_stat == 0) /* got intr signal? */ 1733 0 stevel interrupted = TRUE; 1734 0 stevel } 1735 0 stevel 1736 0 stevel if ((cm_entry->x_state_flags & (X_BADSTATES|X_CONNECTED)) == 1737 0 stevel X_CONNECTED) { 1738 0 stevel clstat = RPC_SUCCESS; 1739 0 stevel } else { 1740 0 stevel if (interrupted == TRUE) 1741 0 stevel clstat = RPC_INTR; 1742 0 stevel RPCLOG(1, "connmgr_cwait: can't connect, error: %s\n", 1743 0 stevel clnt_sperrno(clstat)); 1744 0 stevel } 1745 0 stevel 1746 0 stevel return (clstat); 1747 0 stevel } 1748 0 stevel 1749 0 stevel /* 1750 0 stevel * Primary interface for how RPC grabs a connection. 1751 0 stevel */ 1752 0 stevel static struct cm_xprt * 1753 0 stevel connmgr_wrapget( 1754 0 stevel struct netbuf *retryaddr, 1755 0 stevel const struct timeval *waitp, 1756 0 stevel cku_private_t *p) 1757 0 stevel { 1758 0 stevel struct cm_xprt *cm_entry; 1759 0 stevel 1760 0 stevel cm_entry = connmgr_get(retryaddr, waitp, &p->cku_addr, p->cku_addrfmly, 1761 0 stevel &p->cku_srcaddr, &p->cku_err, p->cku_device, 1762 8778 Erik p->cku_client.cl_nosignal, p->cku_useresvport, p->cku_cred); 1763 0 stevel 1764 0 stevel if (cm_entry == NULL) { 1765 0 stevel /* 1766 0 stevel * Re-map the call status to RPC_INTR if the err code is 1767 0 stevel * EINTR. This can happen if calls status is RPC_TLIERROR. 1768 0 stevel * However, don't re-map if signalling has been turned off. 1769 0 stevel * XXX Really need to create a separate thread whenever 1770 0 stevel * there isn't an existing connection. 1771 0 stevel */ 1772 0 stevel if (p->cku_err.re_errno == EINTR) { 1773 0 stevel if (p->cku_client.cl_nosignal == TRUE) 1774 0 stevel p->cku_err.re_errno = EIO; 1775 0 stevel else 1776 0 stevel p->cku_err.re_status = RPC_INTR; 1777 0 stevel } 1778 0 stevel } 1779 0 stevel 1780 0 stevel return (cm_entry); 1781 0 stevel } 1782 0 stevel 1783 0 stevel /* 1784 0 stevel * Obtains a transport to the server specified in addr. If a suitable transport 1785 0 stevel * does not already exist in the list of cached transports, a new connection 1786 0 stevel * is created, connected, and added to the list. The connection is for sending 1787 0 stevel * only - the reply message may come back on another transport connection. 1788 9806 dai * 1789 9806 dai * To implement round-robin load balancing with multiple client connections, 1790 9806 dai * the last entry on the list is always selected. Once the entry is selected 1791 9806 dai * it's re-inserted to the head of the list. 1792 0 stevel */ 1793 0 stevel static struct cm_xprt * 1794 0 stevel connmgr_get( 1795 0 stevel struct netbuf *retryaddr, 1796 0 stevel const struct timeval *waitp, /* changed to a ptr to converse stack */ 1797 0 stevel struct netbuf *destaddr, 1798 0 stevel int addrfmly, 1799 0 stevel struct netbuf *srcaddr, 1800 0 stevel struct rpc_err *rpcerr, 1801 0 stevel dev_t device, 1802 0 stevel bool_t nosignal, 1803 8778 Erik int useresvport, 1804 8778 Erik cred_t *cr) 1805 0 stevel { 1806 0 stevel struct cm_xprt *cm_entry; 1807 0 stevel struct cm_xprt *lru_entry; 1808 9806 dai struct cm_xprt **cmp, **prev; 1809 0 stevel queue_t *wq; 1810 0 stevel TIUSER *tiptr; 1811 0 stevel int i; 1812 0 stevel int retval; 1813 0 stevel int tidu_size; 1814 0 stevel bool_t connected; 1815 766 carlsonj zoneid_t zoneid = rpc_zoneid(); 1816 0 stevel 1817 0 stevel /* 1818 0 stevel * If the call is not a retry, look for a transport entry that 1819 0 stevel * goes to the server of interest. 1820 0 stevel */ 1821 0 stevel mutex_enter(&connmgr_lock); 1822 0 stevel 1823 0 stevel if (retryaddr == NULL) { 1824 0 stevel use_new_conn: 1825 0 stevel i = 0; 1826 0 stevel cm_entry = lru_entry = NULL; 1827 0 stevel 1828 9806 dai prev = cmp = &cm_hd; 1829 0 stevel while ((cm_entry = *cmp) != NULL) { 1830 0 stevel ASSERT(cm_entry != cm_entry->x_next); 1831 0 stevel /* 1832 0 stevel * Garbage collect conections that are marked 1833 0 stevel * for needs disconnect. 1834 0 stevel */ 1835 0 stevel if (cm_entry->x_needdis) { 1836 154 shepler CONN_HOLD(cm_entry); 1837 0 stevel connmgr_dis_and_wait(cm_entry); 1838 154 shepler connmgr_release(cm_entry); 1839 0 stevel /* 1840 0 stevel * connmgr_lock could have been 1841 0 stevel * dropped for the disconnect 1842 0 stevel * processing so start over. 1843 0 stevel */ 1844 0 stevel goto use_new_conn; 1845 0 stevel } 1846 0 stevel 1847 0 stevel /* 1848 0 stevel * Garbage collect the dead connections that have 1849 0 stevel * no threads working on them. 1850 0 stevel */ 1851 0 stevel if ((cm_entry->x_state_flags & (X_DEAD|X_THREAD)) == 1852 0 stevel X_DEAD) { 1853 3017 maheshvs mutex_enter(&cm_entry->x_lock); 1854 3017 maheshvs if (cm_entry->x_ref != 0) { 1855 3017 maheshvs /* 1856 3017 maheshvs * Currently in use. 1857 3017 maheshvs * Cleanup later. 1858 3017 maheshvs */ 1859 3017 maheshvs cmp = &cm_entry->x_next; 1860 3017 maheshvs mutex_exit(&cm_entry->x_lock); 1861 3017 maheshvs continue; 1862 3017 maheshvs } 1863 3017 maheshvs mutex_exit(&cm_entry->x_lock); 1864 0 stevel *cmp = cm_entry->x_next; 1865 0 stevel mutex_exit(&connmgr_lock); 1866 0 stevel connmgr_close(cm_entry); 1867 0 stevel mutex_enter(&connmgr_lock); 1868 0 stevel goto use_new_conn; 1869 0 stevel } 1870 0 stevel 1871 0 stevel 1872 0 stevel if ((cm_entry->x_state_flags & X_BADSTATES) == 0 && 1873 0 stevel cm_entry->x_zoneid == zoneid && 1874 0 stevel cm_entry->x_rdev == device && 1875 0 stevel destaddr->len == cm_entry->x_server.len && 1876 0 stevel bcmp(destaddr->buf, cm_entry->x_server.buf, 1877 0 stevel destaddr->len) == 0) { 1878 0 stevel /* 1879 0 stevel * If the matching entry isn't connected, 1880 0 stevel * attempt to reconnect it. 1881 0 stevel */ 1882 0 stevel if (cm_entry->x_connected == FALSE) { 1883 0 stevel /* 1884 0 stevel * We don't go through trying 1885 0 stevel * to find the least recently 1886 0 stevel * used connected because 1887 0 stevel * connmgr_reconnect() briefly 1888 0 stevel * dropped the connmgr_lock, 1889 0 stevel * allowing a window for our 1890 0 stevel * accounting to be messed up. 1891 0 stevel * In any case, a re-connected 1892 0 stevel * connection is as good as 1893 0 stevel * a LRU connection. 1894 0 stevel */ 1895 0 stevel return (connmgr_wrapconnect(cm_entry, 1896 0 stevel waitp, destaddr, addrfmly, srcaddr, 1897 8778 Erik rpcerr, TRUE, nosignal, cr)); 1898 0 stevel } 1899 0 stevel i++; 1900 9806 dai 1901 9806 dai /* keep track of the last entry */ 1902 9806 dai lru_entry = cm_entry; 1903 9806 dai prev = cmp; 1904 0 stevel } 1905 0 stevel cmp = &cm_entry->x_next; 1906 0 stevel } 1907 0 stevel 1908 0 stevel if (i > clnt_max_conns) { 1909 0 stevel RPCLOG(8, "connmgr_get: too many conns, dooming entry" 1910 0 stevel " %p\n", (void *)lru_entry->x_tiptr); 1911 0 stevel lru_entry->x_doomed = TRUE; 1912 0 stevel goto use_new_conn; 1913 0 stevel } 1914 0 stevel 1915 0 stevel /* 1916 0 stevel * If we are at the maximum number of connections to 1917 0 stevel * the server, hand back the least recently used one. 1918 0 stevel */ 1919 0 stevel if (i == clnt_max_conns) { 1920 0 stevel /* 1921 0 stevel * Copy into the handle the source address of 1922 0 stevel * the connection, which we will use in case of 1923 0 stevel * a later retry. 1924 0 stevel */ 1925 0 stevel if (srcaddr->len != lru_entry->x_src.len) { 1926 0 stevel if (srcaddr->len > 0) 1927 0 stevel kmem_free(srcaddr->buf, 1928 0 stevel srcaddr->maxlen); 1929 0 stevel srcaddr->buf = kmem_zalloc( 1930 0 stevel lru_entry->x_src.len, KM_SLEEP); 1931 0 stevel srcaddr->maxlen = srcaddr->len = 1932 0 stevel lru_entry->x_src.len; 1933 0 stevel } 1934 0 stevel bcopy(lru_entry->x_src.buf, srcaddr->buf, srcaddr->len); 1935 0 stevel RPCLOG(2, "connmgr_get: call going out on %p\n", 1936 0 stevel (void *)lru_entry); 1937 11066 rafael lru_entry->x_time = ddi_get_lbolt(); 1938 0 stevel CONN_HOLD(lru_entry); 1939 9806 dai 1940 9806 dai if ((i > 1) && (prev != &cm_hd)) { 1941 9806 dai /* 1942 9806 dai * remove and re-insert entry at head of list. 1943 9806 dai */ 1944 9806 dai *prev = lru_entry->x_next; 1945 9806 dai lru_entry->x_next = cm_hd; 1946 9806 dai cm_hd = lru_entry; 1947 9806 dai } 1948 9806 dai 1949 0 stevel mutex_exit(&connmgr_lock); 1950 0 stevel return (lru_entry); 1951 0 stevel } 1952 0 stevel 1953 0 stevel } else { 1954 0 stevel /* 1955 0 stevel * This is the retry case (retryaddr != NULL). Retries must 1956 0 stevel * be sent on the same source port as the original call. 1957 0 stevel */ 1958 0 stevel 1959 0 stevel /* 1960 0 stevel * Walk the list looking for a connection with a source address 1961 0 stevel * that matches the retry address. 1962 0 stevel */ 1963 8806 Gerald start_retry_loop: 1964 0 stevel cmp = &cm_hd; 1965 0 stevel while ((cm_entry = *cmp) != NULL) { 1966 0 stevel ASSERT(cm_entry != cm_entry->x_next); 1967 8806 Gerald 1968 8806 Gerald /* 1969 8806 Gerald * determine if this connection matches the passed 1970 8806 Gerald * in retry address. If it does not match, advance 1971 8806 Gerald * to the next element on the list. 1972 8806 Gerald */ 1973 0 stevel if (zoneid != cm_entry->x_zoneid || 1974 0 stevel device != cm_entry->x_rdev || 1975 0 stevel retryaddr->len != cm_entry->x_src.len || 1976 0 stevel bcmp(retryaddr->buf, cm_entry->x_src.buf, 1977 6403 gt29601 retryaddr->len) != 0) { 1978 0 stevel cmp = &cm_entry->x_next; 1979 0 stevel continue; 1980 8806 Gerald } 1981 8806 Gerald /* 1982 8806 Gerald * Garbage collect conections that are marked 1983 8806 Gerald * for needs disconnect. 1984 8806 Gerald */ 1985 8806 Gerald if (cm_entry->x_needdis) { 1986 8806 Gerald CONN_HOLD(cm_entry); 1987 8806 Gerald connmgr_dis_and_wait(cm_entry); 1988 8806 Gerald connmgr_release(cm_entry); 1989 8806 Gerald /* 1990 8806 Gerald * connmgr_lock could have been 1991 8806 Gerald * dropped for the disconnect 1992 8806 Gerald * processing so start over. 1993 8806 Gerald */ 1994 8806 Gerald goto start_retry_loop; 1995 8806 Gerald } 1996 8806 Gerald /* 1997 8806 Gerald * Garbage collect the dead connections that have 1998 8806 Gerald * no threads working on them. 1999 8806 Gerald */ 2000 8806 Gerald if ((cm_entry->x_state_flags & (X_DEAD|X_THREAD)) == 2001 8806 Gerald X_DEAD) { 2002 8806 Gerald mutex_enter(&cm_entry->x_lock); 2003 8806 Gerald if (cm_entry->x_ref != 0) { 2004 8806 Gerald /* 2005 8806 Gerald * Currently in use. 2006 8806 Gerald * Cleanup later. 2007 8806 Gerald */ 2008 8806 Gerald cmp = &cm_entry->x_next; 2009 8806 Gerald mutex_exit(&cm_entry->x_lock); 2010 8806 Gerald continue; 2011 8806 Gerald } 2012 8806 Gerald mutex_exit(&cm_entry->x_lock); 2013 8806 Gerald *cmp = cm_entry->x_next; 2014 8806 Gerald mutex_exit(&connmgr_lock); 2015 8806 Gerald connmgr_close(cm_entry); 2016 8806 Gerald mutex_enter(&connmgr_lock); 2017 8806 Gerald goto start_retry_loop; 2018 0 stevel } 2019 0 stevel 2020 0 stevel /* 2021 0 stevel * Sanity check: if the connection with our source 2022 0 stevel * port is going to some other server, something went 2023 0 stevel * wrong, as we never delete connections (i.e. release 2024 0 stevel * ports) unless they have been idle. In this case, 2025 0 stevel * it is probably better to send the call out using 2026 0 stevel * a new source address than to fail it altogether, 2027 0 stevel * since that port may never be released. 2028 0 stevel */ 2029 0 stevel if (destaddr->len != cm_entry->x_server.len || 2030 6403 gt29601 bcmp(destaddr->buf, cm_entry->x_server.buf, 2031 6403 gt29601 destaddr->len) != 0) { 2032 0 stevel RPCLOG(1, "connmgr_get: tiptr %p" 2033 0 stevel " is going to a different server" 2034 0 stevel " with the port that belongs" 2035 0 stevel " to us!\n", (void *)cm_entry->x_tiptr); 2036 0 stevel retryaddr = NULL; 2037 0 stevel goto use_new_conn; 2038 0 stevel } 2039 0 stevel 2040 0 stevel /* 2041 0 stevel * If the connection of interest is not connected and we 2042 0 stevel * can't reconnect it, then the server is probably 2043 0 stevel * still down. Return NULL to the caller and let it 2044 0 stevel * retry later if it wants to. We have a delay so the 2045 0 stevel * machine doesn't go into a tight retry loop. If the 2046 0 stevel * entry was already connected, or the reconnected was 2047 0 stevel * successful, return this entry. 2048 0 stevel */ 2049 0 stevel if (cm_entry->x_connected == FALSE) { 2050 0 stevel return (connmgr_wrapconnect(cm_entry, 2051 0 stevel waitp, destaddr, addrfmly, NULL, 2052 8778 Erik rpcerr, TRUE, nosignal, cr)); 2053 0 stevel } else { 2054 0 stevel CONN_HOLD(cm_entry); 2055 0 stevel 2056 11066 rafael cm_entry->x_time = ddi_get_lbolt(); 2057 0 stevel mutex_exit(&connmgr_lock); 2058 0 stevel RPCLOG(2, "connmgr_get: found old " 2059 0 stevel "transport %p for retry\n", 2060 0 stevel (void *)cm_entry); 2061 0 stevel return (cm_entry); 2062 0 stevel } 2063 0 stevel } 2064 0 stevel 2065 0 stevel /* 2066 0 stevel * We cannot find an entry in the list for this retry. 2067 0 stevel * Either the entry has been removed temporarily to be 2068 0 stevel * reconnected by another thread, or the original call 2069 0 stevel * got a port but never got connected, 2070 0 stevel * and hence the transport never got put in the 2071 0 stevel * list. Fall through to the "create new connection" code - 2072 0 stevel * the former case will fail there trying to rebind the port, 2073 0 stevel * and the later case (and any other pathological cases) will 2074 0 stevel * rebind and reconnect and not hang the client machine. 2075 0 stevel */ 2076 0 stevel RPCLOG0(8, "connmgr_get: no entry in list for retry\n"); 2077 0 stevel } 2078 0 stevel /* 2079 0 stevel * Set up a transport entry in the connection manager's list. 2080 0 stevel */ 2081 0 stevel cm_entry = (struct cm_xprt *) 2082 0 stevel kmem_zalloc(sizeof (struct cm_xprt), KM_SLEEP); 2083 0 stevel 2084 0 stevel cm_entry->x_server.buf = kmem_zalloc(destaddr->len, KM_SLEEP); 2085 0 stevel bcopy(destaddr->buf, cm_entry->x_server.buf, destaddr->len); 2086 0 stevel cm_entry->x_server.len = cm_entry->x_server.maxlen = destaddr->len; 2087 0 stevel 2088 0 stevel cm_entry->x_state_flags = X_THREAD; 2089 0 stevel cm_entry->x_ref = 1; 2090 0 stevel cm_entry->x_family = addrfmly; 2091 0 stevel cm_entry->x_rdev = device; 2092 0 stevel cm_entry->x_zoneid = zoneid; 2093 0 stevel mutex_init(&cm_entry->x_lock, NULL, MUTEX_DEFAULT, NULL); 2094 0 stevel cv_init(&cm_entry->x_cv, NULL, CV_DEFAULT, NULL); 2095 0 stevel cv_init(&cm_entry->x_conn_cv, NULL, CV_DEFAULT, NULL); 2096 0 stevel cv_init(&cm_entry->x_dis_cv, NULL, CV_DEFAULT, NULL); 2097 0 stevel 2098 0 stevel /* 2099 0 stevel * Note that we add this partially initialized entry to the 2100 0 stevel * connection list. This is so that we don't have connections to 2101 0 stevel * the same server. 2102 0 stevel * 2103 0 stevel * Note that x_src is not initialized at this point. This is because 2104 0 stevel * retryaddr might be NULL in which case x_src is whatever 2105 0 stevel * t_kbind/bindresvport gives us. If another thread wants a 2106 0 stevel * connection to the same server, seemingly we have an issue, but we 2107 0 stevel * don't. If the other thread comes in with retryaddr == NULL, then it 2108 0 stevel * will never look at x_src, and it will end up waiting in 2109 0 stevel * connmgr_cwait() for the first thread to finish the connection 2110 0 stevel * attempt. If the other thread comes in with retryaddr != NULL, then 2111 0 stevel * that means there was a request sent on a connection, in which case 2112 0 stevel * the the connection should already exist. Thus the first thread 2113 0 stevel * never gets here ... it finds the connection it its server in the 2114 0 stevel * connection list. 2115 0 stevel * 2116 0 stevel * But even if theory is wrong, in the retryaddr != NULL case, the 2nd 2117 0 stevel * thread will skip us because x_src.len == 0. 2118 0 stevel */ 2119 0 stevel cm_entry->x_next = cm_hd; 2120 0 stevel cm_hd = cm_entry; 2121 0 stevel mutex_exit(&connmgr_lock); 2122 0 stevel 2123 0 stevel /* 2124 0 stevel * Either we didn't find an entry to the server of interest, or we 2125 0 stevel * don't have the maximum number of connections to that server - 2126 0 stevel * create a new connection. 2127 0 stevel */ 2128 0 stevel RPCLOG0(8, "connmgr_get: creating new connection\n"); 2129 0 stevel rpcerr->re_status = RPC_TLIERROR; 2130 0 stevel 2131 1676 jpk i = t_kopen(NULL, device, FREAD|FWRITE|FNDELAY, &tiptr, zone_kcred()); 2132 0 stevel if (i) { 2133 0 stevel RPCLOG(1, "connmgr_get: can't open cots device, error %d\n", i); 2134 0 stevel rpcerr->re_errno = i; 2135 0 stevel connmgr_cancelconn(cm_entry); 2136 0 stevel return (NULL); 2137 0 stevel } 2138 0 stevel rpc_poptimod(tiptr->fp->f_vnode); 2139 0 stevel 2140 0 stevel if (i = strioctl(tiptr->fp->f_vnode, I_PUSH, (intptr_t)"rpcmod", 0, 2141 6403 gt29601 K_TO_K, kcred, &retval)) { 2142 0 stevel RPCLOG(1, "connmgr_get: can't push cots module, %d\n", i); 2143 0 stevel (void) t_kclose(tiptr, 1); 2144 0 stevel rpcerr->re_errno = i; 2145 0 stevel connmgr_cancelconn(cm_entry); 2146 0 stevel return (NULL); 2147 0 stevel } 2148 0 stevel 2149 0 stevel if (i = strioctl(tiptr->fp->f_vnode, RPC_CLIENT, 0, 0, K_TO_K, 2150 6403 gt29601 kcred, &retval)) { 2151 0 stevel RPCLOG(1, "connmgr_get: can't set client status with cots " 2152 0 stevel "module, %d\n", i); 2153 0 stevel (void) t_kclose(tiptr, 1); 2154 0 stevel rpcerr->re_errno = i; 2155 0 stevel connmgr_cancelconn(cm_entry); 2156 0 stevel return (NULL); 2157 0 stevel } 2158 0 stevel 2159 0 stevel mutex_enter(&connmgr_lock); 2160 0 stevel 2161 0 stevel wq = tiptr->fp->f_vnode->v_stream->sd_wrq->q_next; 2162 0 stevel cm_entry->x_wq = wq; 2163 0 stevel 2164 0 stevel mutex_exit(&connmgr_lock); 2165 0 stevel 2166 0 stevel if (i = strioctl(tiptr->fp->f_vnode, I_PUSH, (intptr_t)"timod", 0, 2167 6403 gt29601 K_TO_K, kcred, &retval)) { 2168 0 stevel RPCLOG(1, "connmgr_get: can't push timod, %d\n", i); 2169 0 stevel (void) t_kclose(tiptr, 1); 2170 0 stevel rpcerr->re_errno = i; 2171 0 stevel connmgr_cancelconn(cm_entry); 2172 0 stevel return (NULL); 2173 0 stevel } 2174 0 stevel 2175 0 stevel /* 2176 0 stevel * If the caller has not specified reserved port usage then 2177 0 stevel * take the system default. 2178 0 stevel */ 2179 0 stevel if (useresvport == -1) 2180 0 stevel useresvport = clnt_cots_do_bindresvport; 2181 0 stevel 2182 0 stevel if ((useresvport || retryaddr != NULL) && 2183 0 stevel (addrfmly == AF_INET || addrfmly == AF_INET6)) { 2184 0 stevel bool_t alloc_src = FALSE; 2185 0 stevel 2186 0 stevel if (srcaddr->len != destaddr->len) { 2187 0 stevel kmem_free(srcaddr->buf, srcaddr->maxlen); 2188 0 stevel srcaddr->buf = kmem_zalloc(destaddr->len, KM_SLEEP); 2189 0 stevel srcaddr->maxlen = destaddr->len; 2190 0 stevel srcaddr->len = destaddr->len; 2191 0 stevel alloc_src = TRUE; 2192 0 stevel } 2193 0 stevel 2194 0 stevel if ((i = bindresvport(tiptr, retryaddr, srcaddr, TRUE)) != 0) { 2195 0 stevel (void) t_kclose(tiptr, 1); 2196 0 stevel RPCLOG(1, "connmgr_get: couldn't bind, retryaddr: " 2197 6403 gt29601 "%p\n", (void *)retryaddr); 2198 0 stevel 2199 0 stevel /* 2200 0 stevel * 1225408: If we allocated a source address, then it 2201 0 stevel * is either garbage or all zeroes. In that case 2202 0 stevel * we need to clear srcaddr. 2203 0 stevel */ 2204 0 stevel if (alloc_src == TRUE) { 2205 0 stevel kmem_free(srcaddr->buf, srcaddr->maxlen); 2206 0 stevel srcaddr->maxlen = srcaddr->len = 0; 2207 0 stevel srcaddr->buf = NULL; 2208 0 stevel } 2209 0 stevel rpcerr->re_errno = i; 2210 0 stevel connmgr_cancelconn(cm_entry); 2211 0 stevel return (NULL); 2212 0 stevel } 2213 0 stevel } else { 2214 0 stevel if ((i = t_kbind(tiptr, NULL, NULL)) != 0) { 2215 0 stevel RPCLOG(1, "clnt_cots_kcreate: t_kbind: %d\n", i); 2216 0 stevel (void) t_kclose(tiptr, 1); 2217 0 stevel rpcerr->re_errno = i; 2218 0 stevel connmgr_cancelconn(cm_entry); 2219 0 stevel return (NULL); 2220 0 stevel } 2221 0 stevel } 2222 0 stevel 2223 0 stevel { 2224 0 stevel /* 2225 0 stevel * Keep the kernel stack lean. Don't move this call 2226 0 stevel * declaration to the top of this function because a 2227 0 stevel * call is declared in connmgr_wrapconnect() 2228 0 stevel */ 2229 0 stevel calllist_t call; 2230 0 stevel 2231 0 stevel bzero(&call, sizeof (call)); 2232 0 stevel cv_init(&call.call_cv, NULL, CV_DEFAULT, NULL); 2233 0 stevel 2234 0 stevel /* 2235 0 stevel * This is a bound end-point so don't close it's stream. 2236 0 stevel */ 2237 0 stevel connected = connmgr_connect(cm_entry, wq, destaddr, addrfmly, 2238 8778 Erik &call, &tidu_size, FALSE, waitp, nosignal, cr); 2239 0 stevel *rpcerr = call.call_err; 2240 0 stevel cv_destroy(&call.call_cv); 2241 0 stevel 2242 0 stevel } 2243 0 stevel 2244 0 stevel mutex_enter(&connmgr_lock); 2245 0 stevel 2246 0 stevel /* 2247 0 stevel * Set up a transport entry in the connection manager's list. 2248 0 stevel */ 2249 0 stevel cm_entry->x_src.buf = kmem_zalloc(srcaddr->len, KM_SLEEP); 2250 0 stevel bcopy(srcaddr->buf, cm_entry->x_src.buf, srcaddr->len); 2251 0 stevel cm_entry->x_src.len = cm_entry->x_src.maxlen = srcaddr->len; 2252 0 stevel 2253 0 stevel cm_entry->x_tiptr = tiptr; 2254 11066 rafael cm_entry->x_time = ddi_get_lbolt(); 2255 0 stevel 2256 0 stevel if (tiptr->tp_info.servtype == T_COTS_ORD) 2257 0 stevel cm_entry->x_ordrel = TRUE; 2258 0 stevel else 2259 0 stevel cm_entry->x_ordrel = FALSE; 2260 0 stevel 2261 0 stevel cm_entry->x_tidu_size = tidu_size; 2262 0 stevel 2263 4457 vv149972 if (cm_entry->x_early_disc) { 2264 4457 vv149972 /* 2265 4457 vv149972 * We need to check if a disconnect request has come 2266 4457 vv149972 * while we are connected, if so, then we need to 2267 4457 vv149972 * set rpcerr->re_status appropriately before returning 2268 4457 vv149972 * NULL to caller. 2269 4457 vv149972 */ 2270 4457 vv149972 if (rpcerr->re_status == RPC_SUCCESS) 2271 4457 vv149972 rpcerr->re_status = RPC_XPRTFAILED; 2272 0 stevel cm_entry->x_connected = FALSE; 2273 4457 vv149972 } else 2274 0 stevel cm_entry->x_connected = connected; 2275 0 stevel 2276 0 stevel /* 2277 0 stevel * There could be a discrepancy here such that 2278 0 stevel * x_early_disc is TRUE yet connected is TRUE as well 2279 0 stevel * and the connection is actually connected. In that case 2280 0 stevel * lets be conservative and declare the connection as not 2281 0 stevel * connected. 2282 0 stevel */ 2283 0 stevel cm_entry->x_early_disc = FALSE; 2284 0 stevel cm_entry->x_needdis = (cm_entry->x_connected == FALSE); 2285 11066 rafael cm_entry->x_ctime = ddi_get_lbolt(); 2286 0 stevel 2287 0 stevel /* 2288 0 stevel * Notify any threads waiting that the connection attempt is done. 2289 0 stevel */ 2290 0 stevel cm_entry->x_thread = FALSE; 2291 0 stevel cv_broadcast(&cm_entry->x_conn_cv); 2292 0 stevel 2293 0 stevel if (cm_entry->x_connected == FALSE) { 2294 4457 vv149972 mutex_exit(&connmgr_lock); 2295 0 stevel connmgr_release(cm_entry); 2296 0 stevel return (NULL); 2297 0 stevel } 2298 4457 vv149972 2299 4457 vv149972 mutex_exit(&connmgr_lock); 2300 4457 vv149972 2301 0 stevel return (cm_entry); 2302 0 stevel } 2303 0 stevel 2304 0 stevel /* 2305 0 stevel * Keep the cm_xprt entry on the connecton list when making a connection. This 2306 0 stevel * is to prevent multiple connections to a slow server from appearing. 2307 0 stevel * We use the bit field x_thread to tell if a thread is doing a connection 2308 0 stevel * which keeps other interested threads from messing with connection. 2309 0 stevel * Those other threads just wait if x_thread is set. 2310 0 stevel * 2311 0 stevel * If x_thread is not set, then we do the actual work of connecting via 2312 0 stevel * connmgr_connect(). 2313 0 stevel * 2314 0 stevel * mutex convention: called with connmgr_lock held, returns with it released. 2315 0 stevel */ 2316 0 stevel static struct cm_xprt * 2317 0 stevel connmgr_wrapconnect( 2318 0 stevel struct cm_xprt *cm_entry, 2319 0 stevel const struct timeval *waitp, 2320 0 stevel struct netbuf *destaddr, 2321 0 stevel int addrfmly, 2322 0 stevel struct netbuf *srcaddr, 2323 0 stevel struct rpc_err *rpcerr, 2324 0 stevel bool_t reconnect, 2325 8778 Erik bool_t nosignal, 2326 8778 Erik cred_t *cr) 2327 0 stevel { 2328 0 stevel ASSERT(MUTEX_HELD(&connmgr_lock)); 2329 0 stevel /* 2330 0 stevel * Hold this entry as we are about to drop connmgr_lock. 2331 0 stevel */ 2332 0 stevel CONN_HOLD(cm_entry); 2333 0 stevel 2334 0 stevel /* 2335 0 stevel * If there is a thread already making a connection for us, then 2336 0 stevel * wait for it to complete the connection. 2337 0 stevel */ 2338 0 stevel if (cm_entry->x_thread == TRUE) { 2339 0 stevel rpcerr->re_status = connmgr_cwait(cm_entry, waitp, nosignal); 2340 0 stevel 2341 0 stevel if (rpcerr->re_status != RPC_SUCCESS) { 2342 0 stevel mutex_exit(&connmgr_lock); 2343 0 stevel connmgr_release(cm_entry); 2344 0 stevel return (NULL); 2345 0 stevel } 2346 0 stevel } else { 2347 0 stevel bool_t connected; 2348 0 stevel calllist_t call; 2349 0 stevel 2350 0 stevel cm_entry->x_thread = TRUE; 2351 0 stevel 2352 0 stevel while (cm_entry->x_needrel == TRUE) { 2353 0 stevel cm_entry->x_needrel = FALSE; 2354 0 stevel 2355 0 stevel connmgr_sndrel(cm_entry); 2356 0 stevel delay(drv_usectohz(1000000)); 2357 0 stevel 2358 0 stevel mutex_enter(&connmgr_lock); 2359 0 stevel } 2360 0 stevel 2361 0 stevel /* 2362 0 stevel * If we need to send a T_DISCON_REQ, send one. 2363 0 stevel */ 2364 0 stevel connmgr_dis_and_wait(cm_entry); 2365 0 stevel 2366 0 stevel mutex_exit(&connmgr_lock); 2367 0 stevel 2368 0 stevel bzero(&call, sizeof (call)); 2369 0 stevel cv_init(&call.call_cv, NULL, CV_DEFAULT, NULL); 2370 0 stevel 2371 0 stevel connected = connmgr_connect(cm_entry, cm_entry->x_wq, 2372 6403 gt29601 destaddr, addrfmly, &call, &cm_entry->x_tidu_size, 2373 8778 Erik reconnect, waitp, nosignal, cr); 2374 0 stevel 2375 0 stevel *rpcerr = call.call_err; 2376 0 stevel cv_destroy(&call.call_cv); 2377 0 stevel 2378 0 stevel mutex_enter(&connmgr_lock); 2379 0 stevel 2380 0 stevel 2381 4457 vv149972 if (cm_entry->x_early_disc) { 2382 4457 vv149972 /* 2383 4457 vv149972 * We need to check if a disconnect request has come 2384 4457 vv149972 * while we are connected, if so, then we need to 2385 4457 vv149972 * set rpcerr->re_status appropriately before returning 2386 4457 vv149972 * NULL to caller. 2387 4457 vv149972 */ 2388 4457 vv149972 if (rpcerr->re_status == RPC_SUCCESS) 2389 4457 vv149972 rpcerr->re_status = RPC_XPRTFAILED; 2390 0 stevel cm_entry->x_connected = FALSE; 2391 4457 vv149972 } else 2392 0 stevel cm_entry->x_connected = connected; 2393 0 stevel 2394 0 stevel /* 2395 0 stevel * There could be a discrepancy here such that 2396 0 stevel * x_early_disc is TRUE yet connected is TRUE as well 2397 0 stevel * and the connection is actually connected. In that case 2398 0 stevel * lets be conservative and declare the connection as not 2399 0 stevel * connected. 2400 0 stevel */ 2401 0 stevel 2402 0 stevel cm_entry->x_early_disc = FALSE; 2403 0 stevel cm_entry->x_needdis = (cm_entry->x_connected == FALSE); 2404 0 stevel 2405 0 stevel 2406 0 stevel /* 2407 0 stevel * connmgr_connect() may have given up before the connection 2408 0 stevel * actually timed out. So ensure that before the next 2409 0 stevel * connection attempt we do a disconnect. 2410 0 stevel */ 2411 11066 rafael cm_entry->x_ctime = ddi_get_lbolt(); 2412 0 stevel cm_entry->x_thread = FALSE; 2413 0 stevel 2414 0 stevel cv_broadcast(&cm_entry->x_conn_cv); 2415 0 stevel 2416 0 stevel if (cm_entry->x_connected == FALSE) { 2417 0 stevel mutex_exit(&connmgr_lock); 2418 0 stevel connmgr_release(cm_entry); 2419 0 stevel return (NULL); 2420 0 stevel } 2421 0 stevel } 2422 0 stevel 2423 0 stevel if (srcaddr != NULL) { 2424 0 stevel /* 2425 0 stevel * Copy into the handle the 2426 0 stevel * source address of the 2427 0 stevel * connection, which we will use 2428 0 stevel * in case of a later retry. 2429 0 stevel */ 2430 0 stevel if (srcaddr->len != cm_entry->x_src.len) { 2431 0 stevel if (srcaddr->maxlen > 0) 2432 0 stevel kmem_free(srcaddr->buf, srcaddr->maxlen); 2433 0 stevel srcaddr->buf = kmem_zalloc(cm_entry->x_src.len, 2434 0 stevel KM_SLEEP); 2435 0 stevel srcaddr->maxlen = srcaddr->len = 2436 0 stevel cm_entry->x_src.len; 2437 0 stevel } 2438 0 stevel bcopy(cm_entry->x_src.buf, srcaddr->buf, srcaddr->len); 2439 0 stevel } 2440 11066 rafael cm_entry->x_time = ddi_get_lbolt(); 2441 0 stevel mutex_exit(&connmgr_lock); 2442 0 stevel return (cm_entry); 2443 0 stevel } 2444 0 stevel 2445 0 stevel /* 2446 0 stevel * If we need to send a T_DISCON_REQ, send one. 2447 0 stevel */ 2448 0 stevel static void 2449 0 stevel connmgr_dis_and_wait(struct cm_xprt *cm_entry) 2450 0 stevel { 2451 0 stevel ASSERT(MUTEX_HELD(&connmgr_lock)); 2452 0 stevel for (;;) { 2453 0 stevel while (cm_entry->x_needdis == TRUE) { 2454 0 stevel RPCLOG(8, "connmgr_dis_and_wait: need " 2455 6403 gt29601 "T_DISCON_REQ for connection 0x%p\n", 2456 6403 gt29601 (void *)cm_entry); 2457 0 stevel cm_entry->x_needdis = FALSE; 2458 0 stevel cm_entry->x_waitdis = TRUE; 2459 0 stevel 2460 0 stevel connmgr_snddis(cm_entry); 2461 0 stevel 2462 0 stevel mutex_enter(&connmgr_lock); 2463 0 stevel } 2464 0 stevel 2465 0 stevel if (cm_entry->x_waitdis == TRUE) { 2466 0 stevel clock_t timout; 2467 0 stevel 2468 0 stevel RPCLOG(8, "connmgr_dis_and_wait waiting for " 2469 6403 gt29601 "T_DISCON_REQ's ACK for connection %p\n", 2470 6403 gt29601 (void *)cm_entry); 2471 0 stevel 2472 11066 rafael timout = clnt_cots_min_conntout * drv_usectohz(1000000); 2473 0 stevel 2474 0 stevel /* 2475 0 stevel * The TPI spec says that the T_DISCON_REQ 2476 0 stevel * will get acknowledged, but in practice 2477 0 stevel * the ACK may never get sent. So don't 2478 0 stevel * block forever. 2479 0 stevel */ 2480 11066 rafael (void) cv_reltimedwait(&cm_entry->x_dis_cv, 2481 11066 rafael &connmgr_lock, timout, TR_CLOCK_TICK); 2482 0 stevel } 2483 0 stevel /* 2484 0 stevel * If we got the ACK, break. If we didn't, 2485 0 stevel * then send another T_DISCON_REQ. 2486 0 stevel */ 2487 0 stevel if (cm_entry->x_waitdis == FALSE) { 2488 0 stevel break; 2489 0 stevel } else { 2490 0 stevel RPCLOG(8, "connmgr_dis_and_wait: did" 2491 6403 gt29601 "not get T_DISCON_REQ's ACK for " 2492 6403 gt29601 "connection %p\n", (void *)cm_entry); 2493 0 stevel cm_entry->x_needdis = TRUE; 2494 0 stevel } 2495 0 stevel } 2496 0 stevel } 2497 0 stevel 2498 0 stevel static void 2499 0 stevel connmgr_cancelconn(struct cm_xprt *cm_entry) 2500 0 stevel { 2501 0 stevel /* 2502 0 stevel * Mark the connection table entry as dead; the next thread that 2503 0 stevel * goes through connmgr_release() will notice this and deal with it. 2504 0 stevel */ 2505 0 stevel mutex_enter(&connmgr_lock); 2506 0 stevel cm_entry->x_dead = TRUE; 2507 0 stevel 2508 0 stevel /* 2509 0 stevel * Notify any threads waiting for the connection that it isn't 2510 0 stevel * going to happen. 2511 0 stevel */ 2512 0 stevel cm_entry->x_thread = FALSE; 2513 0 stevel cv_broadcast(&cm_entry->x_conn_cv); 2514 0 stevel mutex_exit(&connmgr_lock); 2515 0 stevel 2516 0 stevel connmgr_release(cm_entry); 2517 0 stevel } 2518 0 stevel 2519 0 stevel static void 2520 0 stevel connmgr_close(struct cm_xprt *cm_entry) 2521 0 stevel { 2522 0 stevel mutex_enter(&cm_entry->x_lock); 2523 0 stevel while (cm_entry->x_ref != 0) { 2524 0 stevel /* 2525 0 stevel * Must be a noninterruptible wait. 2526 0 stevel */ 2527 0 stevel cv_wait(&cm_entry->x_cv, &cm_entry->x_lock); 2528 0 stevel } 2529 0 stevel 2530 0 stevel if (cm_entry->x_tiptr != NULL) 2531 0 stevel (void) t_kclose(cm_entry->x_tiptr, 1); 2532 0 stevel 2533 0 stevel mutex_exit(&cm_entry->x_lock); 2534 0 stevel if (cm_entry->x_ksp != NULL) { 2535 0 stevel mutex_enter(&connmgr_lock); 2536 0 stevel cm_entry->x_ksp->ks_private = NULL; 2537 0 stevel mutex_exit(&connmgr_lock); 2538 0 stevel 2539 0 stevel /* 2540 0 stevel * Must free the buffer we allocated for the 2541 0 stevel * server address in the update function 2542 0 stevel */ 2543 0 stevel if (((struct cm_kstat_xprt *)(cm_entry->x_ksp->ks_data))-> 2544 457 bmc x_server.value.str.addr.ptr != NULL) 2545 0 stevel kmem_free(((struct cm_kstat_xprt *)(cm_entry->x_ksp-> 2546 457 bmc ks_data))->x_server.value.str.addr.ptr, 2547 6403 gt29601 INET6_ADDRSTRLEN); 2548 0 stevel kmem_free(cm_entry->x_ksp->ks_data, 2549 6403 gt29601 cm_entry->x_ksp->ks_data_size); 2550 0 stevel kstat_delete(cm_entry->x_ksp); 2551 0 stevel } 2552 0 stevel 2553 0 stevel mutex_destroy(&cm_entry->x_lock); 2554 0 stevel cv_destroy(&cm_entry->x_cv); 2555 0 stevel cv_destroy(&cm_entry->x_conn_cv); 2556 0 stevel cv_destroy(&cm_entry->x_dis_cv); 2557 0 stevel 2558 0 stevel if (cm_entry->x_server.buf != NULL) 2559 0 stevel kmem_free(cm_entry->x_server.buf, cm_entry->x_server.maxlen); 2560 0 stevel if (cm_entry->x_src.buf != NULL) 2561 0 stevel kmem_free(cm_entry->x_src.buf, cm_entry->x_src.maxlen); 2562 0 stevel kmem_free(cm_entry, sizeof (struct cm_xprt)); 2563 0 stevel } 2564 0 stevel 2565 0 stevel /* 2566 0 stevel * Called by KRPC after sending the call message to release the connection 2567 0 stevel * it was using. 2568 0 stevel */ 2569 0 stevel static void 2570 0 stevel connmgr_release(struct cm_xprt *cm_entry) 2571 0 stevel { 2572 0 stevel mutex_enter(&cm_entry->x_lock); 2573 0 stevel cm_entry->x_ref--; 2574 0 stevel if (cm_entry->x_ref == 0) 2575 0 stevel cv_signal(&cm_entry->x_cv); 2576 0 stevel mutex_exit(&cm_entry->x_lock); 2577 0 stevel } 2578 0 stevel 2579 0 stevel /* 2580 10004 dai * Set TCP receive and xmit buffer size for RPC connections. 2581 10004 dai */ 2582 10004 dai static bool_t 2583 10004 dai connmgr_setbufsz(calllist_t *e, queue_t *wq, cred_t *cr) 2584 10004 dai { 2585 10004 dai int ok = FALSE; 2586 10004 dai int val; 2587 10004 dai 2588 10004 dai if (rpc_default_tcp_bufsz) 2589 10004 dai return (FALSE); 2590 10004 dai 2591 10004 dai /* 2592 10004 dai * Only set new buffer size if it's larger than the system 2593 10004 dai * default buffer size. If smaller buffer size is needed 2594 10004 dai * then use /etc/system to set rpc_default_tcp_bufsz to 1. 2595 10004 dai */ 2596 10004 dai ok = connmgr_getopt_int(wq, SOL_SOCKET, SO_RCVBUF, &val, e, cr); 2597 10004 dai if ((ok == TRUE) && (val < rpc_send_bufsz)) { 2598 10004 dai ok = connmgr_setopt_int(wq, SOL_SOCKET, SO_RCVBUF, 2599 10004 dai rpc_send_bufsz, e, cr); 2600 10004 dai DTRACE_PROBE2(krpc__i__connmgr_rcvbufsz, 2601 10004 dai int, ok, calllist_t *, e); 2602 10004 dai } 2603 10004 dai 2604 10004 dai ok = connmgr_getopt_int(wq, SOL_SOCKET, SO_SNDBUF, &val, e, cr); 2605 10004 dai if ((ok == TRUE) && (val < rpc_recv_bufsz)) { 2606 10004 dai ok = connmgr_setopt_int(wq, SOL_SOCKET, SO_SNDBUF, 2607 10004 dai rpc_recv_bufsz, e, cr); 2608 10004 dai DTRACE_PROBE2(krpc__i__connmgr_sndbufsz, 2609 10004 dai int, ok, calllist_t *, e); 2610 10004 dai } 2611 10004 dai return (TRUE); 2612 10004 dai } 2613 10004 dai 2614 10004 dai /* 2615 0 stevel * Given an open stream, connect to the remote. Returns true if connected, 2616 0 stevel * false otherwise. 2617 0 stevel */ 2618 0 stevel static bool_t 2619 0 stevel connmgr_connect( 2620 0 stevel struct cm_xprt *cm_entry, 2621 0 stevel queue_t *wq, 2622 0 stevel struct netbuf *addr, 2623 0 stevel int addrfmly, 2624 0 stevel calllist_t *e, 2625 0 stevel int *tidu_ptr, 2626 0 stevel bool_t reconnect, 2627 0 stevel const struct timeval *waitp, 2628 8778 Erik bool_t nosignal, 2629 8778 Erik cred_t *cr) 2630 0 stevel { 2631 0 stevel mblk_t *mp; 2632 0 stevel struct T_conn_req *tcr; 2633 0 stevel struct T_info_ack *tinfo; 2634 0 stevel int interrupted, error; 2635 0 stevel int tidu_size, kstat_instance; 2636 0 stevel 2637 0 stevel /* if it's a reconnect, flush any lingering data messages */ 2638 0 stevel if (reconnect) 2639 0 stevel (void) putctl1(wq, M_FLUSH, FLUSHRW); 2640 0 stevel 2641 8778 Erik /* 2642 8778 Erik * Note: if the receiver uses SCM_UCRED/getpeerucred the pid will 2643 8778 Erik * appear as -1. 2644 8778 Erik */ 2645 8778 Erik mp = allocb_cred(sizeof (*tcr) + addr->len, cr, NOPID); 2646 0 stevel if (mp == NULL) { 2647 0 stevel /* 2648 0 stevel * This is unfortunate, but we need to look up the stats for 2649 0 stevel * this zone to increment the "memory allocation failed" 2650 0 stevel * counter. curproc->p_zone is safe since we're initiating a 2651 0 stevel * connection and not in some strange streams context. 2652 0 stevel */ 2653 0 stevel struct rpcstat *rpcstat; 2654 0 stevel 2655 766 carlsonj rpcstat = zone_getspecific(rpcstat_zone_key, rpc_zone()); 2656 0 stevel ASSERT(rpcstat != NULL); 2657 0 stevel 2658 0 stevel RPCLOG0(1, "connmgr_connect: cannot alloc mp for " 2659 0 stevel "sending conn request\n"); 2660 0 stevel COTSRCSTAT_INCR(rpcstat->rpc_cots_client, rcnomem); 2661 0 stevel e->call_status = RPC_SYSTEMERROR; 2662 0 stevel e->call_reason = ENOSR; 2663 0 stevel return (FALSE); 2664 0 stevel } 2665 10004 dai 2666 10004 dai /* Set TCP buffer size for RPC connections if needed */ 2667 10004 dai if (addrfmly == AF_INET || addrfmly == AF_INET6) 2668 10004 dai (void) connmgr_setbufsz(e, wq, cr); 2669 0 stevel 2670 0 stevel mp->b_datap->db_type = M_PROTO; 2671 0 stevel tcr = (struct T_conn_req *)mp->b_rptr; 2672 0 stevel bzero(tcr, sizeof (*tcr)); 2673 0 stevel tcr->PRIM_type = T_CONN_REQ; 2674 0 stevel tcr->DEST_length = addr->len; 2675 0 stevel tcr->DEST_offset = sizeof (struct T_conn_req); 2676 0 stevel mp->b_wptr = mp->b_rptr + sizeof (*tcr); 2677 0 stevel 2678 0 stevel bcopy(addr->buf, mp->b_wptr, tcr->DEST_length); 2679 0 stevel mp->b_wptr += tcr->DEST_length; 2680 0 stevel 2681 0 stevel RPCLOG(8, "connmgr_connect: sending conn request on queue " 2682 0 stevel "%p", (void *)wq); 2683 0 stevel RPCLOG(8, " call %p\n", (void *)wq); 2684 0 stevel /* 2685 0 stevel * We use the entry in the handle that is normally used for 2686 0 stevel * waiting for RPC replies to wait for the connection accept. 2687 0 stevel */ 2688 8205 Siddheshwar if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) { 2689 8205 Siddheshwar DTRACE_PROBE(krpc__e__connmgr__connect__cantsend); 2690 8205 Siddheshwar freemsg(mp); 2691 8205 Siddheshwar return (FALSE); 2692 8205 Siddheshwar } 2693 0 stevel 2694 0 stevel mutex_enter(&clnt_pending_lock); 2695 0 stevel 2696 0 stevel /* 2697 0 stevel * We wait for the transport connection to be made, or an 2698 0 stevel * indication that it could not be made. 2699 0 stevel */ 2700 0 stevel interrupted = 0; 2701 0 stevel 2702 0 stevel /* 2703 0 stevel * waitforack should have been called with T_OK_ACK, but the 2704 0 stevel * present implementation needs to be passed T_INFO_ACK to 2705 0 stevel * work correctly. 2706 0 stevel */ 2707 0 stevel error = waitforack(e, T_INFO_ACK, waitp, nosignal); 2708 0 stevel if (error == EINTR) 2709 0 stevel interrupted = 1; 2710 0 stevel if (zone_status_get(curproc->p_zone) >= ZONE_IS_EMPTY) { 2711 0 stevel /* 2712 0 stevel * No time to lose; we essentially have been signaled to 2713 0 stevel * quit. 2714 0 stevel */ 2715 0 stevel interrupted = 1; 2716 0 stevel } 2717 0 stevel #ifdef RPCDEBUG 2718 0 stevel if (error == ETIME) 2719 0 stevel RPCLOG0(8, "connmgr_connect: giving up " 2720 0 stevel "on connection attempt; " 2721 0 stevel "clnt_dispatch notifyconn " 2722 0 stevel "diagnostic 'no one waiting for " 2723 0 stevel "connection' should not be " 2724 0 stevel "unexpected\n"); 2725 0 stevel #endif 2726 0 stevel if (e->call_prev) 2727 0 stevel e->call_prev->call_next = e->call_next; 2728 0 stevel else 2729 0 stevel clnt_pending = e->call_next; 2730 0 stevel if (e->call_next) 2731 0 stevel e->call_next->call_prev = e->call_prev; 2732 0 stevel mutex_exit(&clnt_pending_lock); 2733 0 stevel 2734 0 stevel if (e->call_status != RPC_SUCCESS || error != 0) { 2735 0 stevel if (interrupted) 2736 0 stevel e->call_status = RPC_INTR; 2737 0 stevel else if (error == ETIME) 2738 0 stevel e->call_status = RPC_TIMEDOUT; 2739 9804 Gerald else if (error == EPROTO) { 2740 0 stevel e->call_status = RPC_SYSTEMERROR; 2741 9804 Gerald e->call_reason = EPROTO; 2742 9804 Gerald } 2743 0 stevel 2744 0 stevel RPCLOG(8, "connmgr_connect: can't connect, status: " 2745 0 stevel "%s\n", clnt_sperrno(e->call_status)); 2746 0 stevel 2747 0 stevel if (e->call_reply) { 2748 0 stevel freemsg(e->call_reply); 2749 0 stevel e->call_reply = NULL; 2750 0 stevel } 2751 0 stevel 2752 0 stevel return (FALSE); 2753 0 stevel } 2754 0 stevel /* 2755 0 stevel * The result of the "connection accept" is a T_info_ack 2756 0 stevel * in the call_reply field. 2757 0 stevel */ 2758 0 stevel ASSERT(e->call_reply != NULL); 2759 0 stevel mp = e->call_reply; 2760 0 stevel e->call_reply = NULL; 2761 0 stevel tinfo = (struct T_info_ack *)mp->b_rptr; 2762 0 stevel 2763 0 stevel tidu_size = tinfo->TIDU_size; 2764 0 stevel tidu_size -= (tidu_size % BYTES_PER_XDR_UNIT); 2765 0 stevel if (tidu_size > COTS_DEFAULT_ALLOCSIZE || (tidu_size <= 0)) 2766 0 stevel tidu_size = COTS_DEFAULT_ALLOCSIZE; 2767 0 stevel *tidu_ptr = tidu_size; 2768 0 stevel 2769 0 stevel freemsg(mp); 2770 0 stevel 2771 0 stevel /* 2772 0 stevel * Set up the pertinent options. NODELAY is so the transport doesn't 2773 0 stevel * buffer up RPC messages on either end. This may not be valid for 2774 0 stevel * all transports. Failure to set this option is not cause to 2775 0 stevel * bail out so we return success anyway. Note that lack of NODELAY 2776 0 stevel * or some other way to flush the message on both ends will cause 2777 0 stevel * lots of retries and terrible performance. 2778 0 stevel */ 2779 0 stevel if (addrfmly == AF_INET || addrfmly == AF_INET6) { 2780 8778 Erik (void) connmgr_setopt(wq, IPPROTO_TCP, TCP_NODELAY, e, cr); 2781 0 stevel if (e->call_status == RPC_XPRTFAILED) 2782 0 stevel return (FALSE); 2783 0 stevel } 2784 0 stevel 2785 0 stevel /* 2786 0 stevel * Since we have a connection, we now need to figure out if 2787 0 stevel * we need to create a kstat. If x_ksp is not NULL then we 2788 0 stevel * are reusing a connection and so we do not need to create 2789 0 stevel * another kstat -- lets just return. 2790 0 stevel */ 2791 0 stevel if (cm_entry->x_ksp != NULL) 2792 0 stevel return (TRUE); 2793 0 stevel 2794 0 stevel /* 2795 0 stevel * We need to increment rpc_kstat_instance atomically to prevent 2796 0 stevel * two kstats being created with the same instance. 2797 0 stevel */ 2798 0 stevel kstat_instance = atomic_add_32_nv((uint32_t *)&rpc_kstat_instance, 1); 2799 0 stevel 2800 0 stevel if ((cm_entry->x_ksp = kstat_create_zone("unix", kstat_instance, 2801 0 stevel "rpc_cots_connections", "rpc", KSTAT_TYPE_NAMED, 2802 0 stevel (uint_t)(sizeof (cm_kstat_xprt_t) / sizeof (kstat_named_t)), 2803 0 stevel KSTAT_FLAG_VIRTUAL, cm_entry->x_zoneid)) == NULL) { 2804 0 stevel return (TRUE); 2805 6403 gt29601 } 2806 0 stevel 2807 0 stevel cm_entry->x_ksp->ks_lock = &connmgr_lock; 2808 0 stevel cm_entry->x_ksp->ks_private = cm_entry; 2809 0 stevel cm_entry->x_ksp->ks_data_size = ((INET6_ADDRSTRLEN * sizeof (char)) 2810 6403 gt29601 + sizeof (cm_kstat_template)); 2811 0 stevel cm_entry->x_ksp->ks_data = kmem_alloc(cm_entry->x_ksp->ks_data_size, 2812 6403 gt29601 KM_SLEEP); 2813 0 stevel bcopy(&cm_kstat_template, cm_entry->x_ksp->ks_data, 2814 0 stevel cm_entry->x_ksp->ks_data_size); 2815 0 stevel ((struct cm_kstat_xprt *)(cm_entry->x_ksp->ks_data))-> 2816 6403 gt29601 x_server.value.str.addr.ptr = 2817 6403 gt29601 kmem_alloc(INET6_ADDRSTRLEN, KM_SLEEP); 2818 0 stevel 2819 0 stevel cm_entry->x_ksp->ks_update = conn_kstat_update; 2820 0 stevel kstat_install(cm_entry->x_ksp); 2821 0 stevel return (TRUE); 2822 0 stevel } 2823 0 stevel 2824 0 stevel /* 2825 10004 dai * Verify that the specified offset falls within the mblk and 2826 10004 dai * that the resulting pointer is aligned. 2827 10004 dai * Returns NULL if not. 2828 10004 dai * 2829 10004 dai * code from fs/sockfs/socksubr.c 2830 10004 dai */ 2831 10004 dai static void * 2832 10004 dai connmgr_opt_getoff(mblk_t *mp, t_uscalar_t offset, 2833 10004 dai t_uscalar_t length, uint_t align_size) 2834 10004 dai { 2835 10004 dai uintptr_t ptr1, ptr2; 2836 10004 dai 2837 10004 dai ASSERT(mp && mp->b_wptr >= mp->b_rptr); 2838 10004 dai ptr1 = (uintptr_t)mp->b_rptr + offset; 2839 10004 dai ptr2 = (uintptr_t)ptr1 + length; 2840 10004 dai if (ptr1 < (uintptr_t)mp->b_rptr || ptr2 > (uintptr_t)mp->b_wptr) { 2841 10004 dai return (NULL); 2842 10004 dai } 2843 10004 dai if ((ptr1 & (align_size - 1)) != 0) { 2844 10004 dai return (NULL); 2845 10004 dai } 2846 10004 dai return ((void *)ptr1); 2847 10004 dai } 2848 10004 dai 2849 10004 dai static bool_t 2850 10004 dai connmgr_getopt_int(queue_t *wq, int level, int name, int *val, 2851 10004 dai calllist_t *e, cred_t *cr) 2852 10004 dai { 2853 10004 dai mblk_t *mp; 2854 10004 dai struct opthdr *opt, *opt_res; 2855 10004 dai struct T_optmgmt_req *tor; 2856 10004 dai struct T_optmgmt_ack *opt_ack; 2857 10004 dai struct timeval waitp; 2858 10004 dai int error; 2859 10004 dai 2860 10004 dai mp = allocb_cred(sizeof (struct T_optmgmt_req) + 2861 10004 dai sizeof (struct opthdr) + sizeof (int), cr, NOPID); 2862 10004 dai if (mp == NULL) 2863 10004 dai return (FALSE); 2864 10004 dai 2865 10004 dai mp->b_datap->db_type = M_PROTO; 2866 10004 dai tor = (struct T_optmgmt_req *)(mp->b_rptr); 2867 10004 dai tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 2868 10004 dai tor->MGMT_flags = T_CURRENT; 2869 10004 dai tor->OPT_length = sizeof (struct opthdr) + sizeof (int); 2870 10004 dai tor->OPT_offset = sizeof (struct T_optmgmt_req); 2871 10004 dai 2872 10004 dai opt = (struct opthdr *)(mp->b_rptr + sizeof (struct T_optmgmt_req)); 2873 10004 dai opt->level = level; 2874 10004 dai opt->name = name; 2875 10004 dai opt->len = sizeof (int); 2876 10004 dai mp->b_wptr += sizeof (struct T_optmgmt_req) + sizeof (struct opthdr) + 2877 10004 dai sizeof (int); 2878 10004 dai 2879 10004 dai /* 2880 10004 dai * We will use this connection regardless 2881 10004 dai * of whether or not the option is readable. 2882 10004 dai */ 2883 10004 dai if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) { 2884 10004 dai DTRACE_PROBE(krpc__e__connmgr__getopt__cantsend); 2885 10004 dai freemsg(mp); 2886 10004 dai return (FALSE); 2887 10004 dai } 2888 10004 dai 2889 10004 dai mutex_enter(&clnt_pending_lock); 2890 10004 dai 2891 10004 dai waitp.tv_sec = clnt_cots_min_conntout; 2892 10004 dai waitp.tv_usec = 0; 2893 10004 dai error = waitforack(e, T_OPTMGMT_ACK, &waitp, 1); 2894 10004 dai 2895 10004 dai if (e->call_prev) 2896 10004 dai e->call_prev->call_next = e->call_next; 2897 10004 dai else 2898 10004 dai clnt_pending = e->call_next; 2899 10004 dai if (e->call_next) 2900 10004 dai e->call_next->call_prev = e->call_prev; 2901 10004 dai mutex_exit(&clnt_pending_lock); 2902 10004 dai 2903 10004 dai /* get reply message */ 2904 10004 dai mp = e->call_reply; 2905 10004 dai e->call_reply = NULL; 2906 10004 dai 2907 10004 dai if ((!mp) || (e->call_status != RPC_SUCCESS) || (error != 0)) { 2908 10004 dai 2909 10004 dai DTRACE_PROBE4(krpc__e__connmgr_getopt, int, name, 2910 10004 dai int, e->call_status, int, error, mblk_t *, mp); 2911 10004 dai 2912 10004 dai if (mp) 2913 10004 dai freemsg(mp); 2914 10004 dai return (FALSE); 2915 10004 dai } 2916 10004 dai 2917 10004 dai opt_ack = (struct T_optmgmt_ack *)mp->b_rptr; 2918 10004 dai opt_res = (struct opthdr *)connmgr_opt_getoff(mp, opt_ack->OPT_offset, 2919 10004 dai opt_ack->OPT_length, __TPI_ALIGN_SIZE); 2920 10004 dai 2921 10004 dai if (!opt_res) { 2922 10004 dai DTRACE_PROBE4(krpc__e__connmgr_optres, mblk_t *, mp, int, name, 2923 10004 dai int, opt_ack->OPT_offset, int, opt_ack->OPT_length); 2924 10004 dai freemsg(mp); 2925 10004 dai return (FALSE); 2926 10004 dai } 2927 10004 dai *val = *(int *)&opt_res[1]; 2928 10004 dai 2929 10004 dai DTRACE_PROBE2(connmgr_getopt__ok, int, name, int, *val); 2930 10004 dai 2931 10004 dai freemsg(mp); 2932 10004 dai return (TRUE); 2933 10004 dai } 2934 10004 dai 2935 10004 dai /* 2936 0 stevel * Called by connmgr_connect to set an option on the new stream. 2937 0 stevel */ 2938 0 stevel static bool_t 2939 10004 dai connmgr_setopt_int(queue_t *wq, int level, int name, int val, 2940 10004 dai calllist_t *e, cred_t *cr) 2941 0 stevel { 2942 0 stevel mblk_t *mp; 2943 0 stevel struct opthdr *opt; 2944 0 stevel struct T_optmgmt_req *tor; 2945 0 stevel struct timeval waitp; 2946 0 stevel int error; 2947 0 stevel 2948 8778 Erik mp = allocb_cred(sizeof (struct T_optmgmt_req) + 2949 8778 Erik sizeof (struct opthdr) + sizeof (int), cr, NOPID); 2950 0 stevel if (mp == NULL) { 2951 0 stevel RPCLOG0(1, "connmgr_setopt: cannot alloc mp for option " 2952 0 stevel "request\n"); 2953 0 stevel return (FALSE); 2954 0 stevel } 2955 0 stevel 2956 0 stevel mp->b_datap->db_type = M_PROTO; 2957 0 stevel tor = (struct T_optmgmt_req *)(mp->b_rptr); 2958 0 stevel tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 2959 0 stevel tor->MGMT_flags = T_NEGOTIATE; 2960 0 stevel tor->OPT_length = sizeof (struct opthdr) + sizeof (int); 2961 0 stevel tor->OPT_offset = sizeof (struct T_optmgmt_req); 2962 0 stevel 2963 0 stevel opt = (struct opthdr *)(mp->b_rptr + sizeof (struct T_optmgmt_req)); 2964 0 stevel opt->level = level; 2965 0 stevel opt->name = name; 2966 0 stevel opt->len = sizeof (int); 2967 10004 dai *(int *)((char *)opt + sizeof (*opt)) = val; 2968 0 stevel mp->b_wptr += sizeof (struct T_optmgmt_req) + sizeof (struct opthdr) + 2969 0 stevel sizeof (int); 2970 0 stevel 2971 0 stevel /* 2972 0 stevel * We will use this connection regardless 2973 0 stevel * of whether or not the option is settable. 2974 0 stevel */ 2975 8205 Siddheshwar if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) { 2976 8205 Siddheshwar DTRACE_PROBE(krpc__e__connmgr__setopt__cantsend); 2977 8205 Siddheshwar freemsg(mp); 2978 8205 Siddheshwar return (FALSE); 2979 8205 Siddheshwar } 2980 8205 Siddheshwar 2981 0 stevel mutex_enter(&clnt_pending_lock); 2982 0 stevel 2983 0 stevel waitp.tv_sec = clnt_cots_min_conntout; 2984 0 stevel waitp.tv_usec = 0; 2985 0 stevel error = waitforack(e, T_OPTMGMT_ACK, &waitp, 1); 2986 0 stevel 2987 0 stevel if (e->call_prev) 2988 0 stevel e->call_prev->call_next = e->call_next; 2989 0 stevel else 2990 0 stevel clnt_pending = e->call_next; 2991 0 stevel if (e->call_next) 2992 0 stevel e->call_next->call_prev = e->call_prev; 2993 0 stevel mutex_exit(&clnt_pending_lock); 2994 0 stevel 2995 0 stevel if (e->call_reply != NULL) { 2996 0 stevel freemsg(e->call_reply); 2997 0 stevel e->call_reply = NULL; 2998 0 stevel } 2999 0 stevel 3000 0 stevel if (e->call_status != RPC_SUCCESS || error != 0) { 3001 0 stevel RPCLOG(1, "connmgr_setopt: can't set option: %d\n", name); 3002 0 stevel return (FALSE); 3003 0 stevel } 3004 0 stevel RPCLOG(8, "connmgr_setopt: successfully set option: %d\n", name); 3005 0 stevel return (TRUE); 3006 10004 dai } 3007 10004 dai 3008 10004 dai static bool_t 3009 10004 dai connmgr_setopt(queue_t *wq, int level, int name, calllist_t *e, cred_t *cr) 3010 10004 dai { 3011 10004 dai return (connmgr_setopt_int(wq, level, name, 1, e, cr)); 3012 0 stevel } 3013 0 stevel 3014 0 stevel #ifdef DEBUG 3015 0 stevel 3016 0 stevel /* 3017 0 stevel * This is a knob to let us force code coverage in allocation failure 3018 0 stevel * case. 3019 0 stevel */ 3020 0 stevel static int connmgr_failsnd; 3021 0 stevel #define CONN_SND_ALLOC(Size, Pri) \ 3022 0 stevel ((connmgr_failsnd-- > 0) ? NULL : allocb(Size, Pri)) 3023 0 stevel 3024 0 stevel #else 3025 0 stevel 3026 0 stevel #define CONN_SND_ALLOC(Size, Pri) allocb(Size, Pri) 3027 0 stevel 3028 0 stevel #endif 3029 0 stevel 3030 0 stevel /* 3031 0 stevel * Sends an orderly release on the specified queue. 3032 0 stevel * Entered with connmgr_lock. Exited without connmgr_lock 3033 0 stevel */ 3034 0 stevel static void 3035 0 stevel connmgr_sndrel(struct cm_xprt *cm_entry) 3036 0 stevel { 3037 0 stevel struct T_ordrel_req *torr; 3038 0 stevel mblk_t *mp; 3039 0 stevel queue_t *q = cm_entry->x_wq; 3040 0 stevel ASSERT(MUTEX_HELD(&connmgr_lock)); 3041 0 stevel mp = CONN_SND_ALLOC(sizeof (struct T_ordrel_req), BPRI_LO); 3042 0 stevel if (mp == NULL) { 3043 0 stevel cm_entry->x_needrel = TRUE; 3044 0 stevel mutex_exit(&connmgr_lock); 3045 0 stevel RPCLOG(1, "connmgr_sndrel: cannot alloc mp for sending ordrel " 3046 6403 gt29601 "to queue %p\n", (void *)q); 3047 0 stevel return; 3048 0 stevel } 3049 0 stevel mutex_exit(&connmgr_lock); 3050 0 stevel 3051 0 stevel mp->b_datap->db_type = M_PROTO; 3052 0 stevel torr = (struct T_ordrel_req *)(mp->b_rptr); 3053 0 stevel torr->PRIM_type = T_ORDREL_REQ; 3054 0 stevel mp->b_wptr = mp->b_rptr + sizeof (struct T_ordrel_req); 3055 0 stevel 3056 0 stevel RPCLOG(8,