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