Print this page
4953763 Need way to configure NFS window sizes without changing system wide defaults
6216670 NFS server needs a bigger transmit buffer


 173 #include <sys/systm.h>
 174 #include <sys/kstat.h>
 175 #include <sys/t_lock.h>
 176 #include <sys/ddi.h>
 177 #include <sys/cmn_err.h>
 178 #include <sys/time.h>
 179 #include <sys/isa_defs.h>
 180 #include <sys/callb.h>
 181 #include <sys/sunddi.h>
 182 #include <sys/atomic.h>
 183 #include <sys/sdt.h>
 184 
 185 #include <netinet/in.h>
 186 #include <netinet/tcp.h>
 187 
 188 #include <rpc/types.h>
 189 #include <rpc/xdr.h>
 190 #include <rpc/auth.h>
 191 #include <rpc/clnt.h>
 192 #include <rpc/rpc_msg.h>

 193 
 194 #define COTS_DEFAULT_ALLOCSIZE  2048
 195 
 196 #define WIRE_HDR_SIZE   20      /* serialized call header, sans proc number */
 197 #define MSG_OFFSET      128     /* offset of call into the mblk */
 198 
 199 const char *kinet_ntop6(uchar_t *, char *, size_t);
 200 
 201 static int      clnt_cots_ksettimers(CLIENT *, struct rpc_timers *,
 202     struct rpc_timers *, int, void(*)(int, int, caddr_t), caddr_t, uint32_t);
 203 static enum clnt_stat   clnt_cots_kcallit(CLIENT *, rpcproc_t, xdrproc_t,
 204     caddr_t, xdrproc_t, caddr_t, struct timeval);
 205 static void     clnt_cots_kabort(CLIENT *);
 206 static void     clnt_cots_kerror(CLIENT *, struct rpc_err *);
 207 static bool_t   clnt_cots_kfreeres(CLIENT *, xdrproc_t, caddr_t);
 208 static void     clnt_cots_kdestroy(CLIENT *);
 209 static bool_t   clnt_cots_kcontrol(CLIENT *, int, char *);
 210 
 211 
 212 /* List of transports managed by the connection manager. */


 364         XDR                     cku_inxdr;      /* xdr routine for input */
 365         char                    cku_rpchdr[WIRE_HDR_SIZE + 4];
 366                                                 /* pre-serialized rpc header */
 367 
 368         uint_t                  cku_outbuflen;  /* default output mblk length */
 369         struct cred             *cku_cred;      /* credentials */
 370         bool_t                  cku_nodelayonerr;
 371                                                 /* for CLSET_NODELAYONERR */
 372         int                     cku_useresvport; /* Use reserved port */
 373         struct rpc_cots_client  *cku_stats;     /* stats for zone */
 374 } cku_private_t;
 375 
 376 static struct cm_xprt *connmgr_wrapconnect(struct cm_xprt *,
 377         const struct timeval *, struct netbuf *, int, struct netbuf *,
 378         struct rpc_err *, bool_t, bool_t, cred_t *);
 379 
 380 static bool_t   connmgr_connect(struct cm_xprt *, queue_t *, struct netbuf *,
 381                                 int, calllist_t *, int *, bool_t reconnect,
 382                                 const struct timeval *, bool_t, cred_t *);
 383 




 384 static bool_t   connmgr_setopt(queue_t *, int, int, calllist_t *, cred_t *cr);
 385 static void     connmgr_sndrel(struct cm_xprt *);
 386 static void     connmgr_snddis(struct cm_xprt *);
 387 static void     connmgr_close(struct cm_xprt *);
 388 static void     connmgr_release(struct cm_xprt *);
 389 static struct cm_xprt *connmgr_wrapget(struct netbuf *, const struct timeval *,
 390         cku_private_t *);
 391 
 392 static struct cm_xprt *connmgr_get(struct netbuf *, const struct timeval *,
 393         struct netbuf *, int, struct netbuf *, struct rpc_err *, dev_t,
 394         bool_t, int, cred_t *);
 395 
 396 static void connmgr_cancelconn(struct cm_xprt *);
 397 static enum clnt_stat connmgr_cwait(struct cm_xprt *, const struct timeval *,
 398         bool_t);
 399 static void connmgr_dis_and_wait(struct cm_xprt *);
 400 
 401 static int      clnt_dispatch_send(queue_t *, mblk_t *, calllist_t *, uint_t,
 402                                         uint_t);
 403 


 485 #define htop(h)         ((cku_private_t *)((h)->cl_private))
 486 
 487 /*
 488  * Times to retry
 489  */
 490 #define REFRESHES       2       /* authentication refreshes */
 491 
 492 /*
 493  * The following is used to determine the global default behavior for
 494  * COTS when binding to a local port.
 495  *
 496  * If the value is set to 1 the default will be to select a reserved
 497  * (aka privileged) port, if the value is zero the default will be to
 498  * use non-reserved ports.  Users of kRPC may override this by using
 499  * CLNT_CONTROL() and CLSET_BINDRESVPORT.
 500  */
 501 int clnt_cots_do_bindresvport = 1;
 502 
 503 static zone_key_t zone_cots_key;
 504 


 505 /*














 506  * We need to do this after all kernel threads in the zone have exited.
 507  */
 508 /* ARGSUSED */
 509 static void
 510 clnt_zone_destroy(zoneid_t zoneid, void *unused)
 511 {
 512         struct cm_xprt **cmp;
 513         struct cm_xprt *cm_entry;
 514         struct cm_xprt *freelist = NULL;
 515 
 516         mutex_enter(&connmgr_lock);
 517         cmp = &cm_hd;
 518         while ((cm_entry = *cmp) != NULL) {
 519                 if (cm_entry->x_zoneid == zoneid) {
 520                         *cmp = cm_entry->x_next;
 521                         cm_entry->x_next = freelist;
 522                         freelist = cm_entry;
 523                 } else {
 524                         cmp = &cm_entry->x_next;
 525                 }


2541         if (cm_entry->x_src.buf != NULL)
2542                 kmem_free(cm_entry->x_src.buf, cm_entry->x_src.maxlen);
2543         kmem_free(cm_entry, sizeof (struct cm_xprt));
2544 }
2545 
2546 /*
2547  * Called by KRPC after sending the call message to release the connection
2548  * it was using.
2549  */
2550 static void
2551 connmgr_release(struct cm_xprt *cm_entry)
2552 {
2553         mutex_enter(&cm_entry->x_lock);
2554         cm_entry->x_ref--;
2555         if (cm_entry->x_ref == 0)
2556                 cv_signal(&cm_entry->x_cv);
2557         mutex_exit(&cm_entry->x_lock);
2558 }
2559 
2560 /*






















































2561  * Given an open stream, connect to the remote.  Returns true if connected,
2562  * false otherwise.
2563  */
2564 static bool_t
2565 connmgr_connect(
2566         struct cm_xprt          *cm_entry,
2567         queue_t                 *wq,
2568         struct netbuf           *addr,
2569         int                     addrfmly,
2570         calllist_t              *e,
2571         int                     *tidu_ptr,
2572         bool_t                  reconnect,
2573         const struct timeval    *waitp,
2574         bool_t                  nosignal,
2575         cred_t                  *cr)
2576 {
2577         mblk_t *mp;
2578         struct T_conn_req *tcr;
2579         struct T_info_ack *tinfo;
2580         int interrupted, error;


2592         if (mp == NULL) {
2593                 /*
2594                  * This is unfortunate, but we need to look up the stats for
2595                  * this zone to increment the "memory allocation failed"
2596                  * counter.  curproc->p_zone is safe since we're initiating a
2597                  * connection and not in some strange streams context.
2598                  */
2599                 struct rpcstat *rpcstat;
2600 
2601                 rpcstat = zone_getspecific(rpcstat_zone_key, rpc_zone());
2602                 ASSERT(rpcstat != NULL);
2603 
2604                 RPCLOG0(1, "connmgr_connect: cannot alloc mp for "
2605                     "sending conn request\n");
2606                 COTSRCSTAT_INCR(rpcstat->rpc_cots_client, rcnomem);
2607                 e->call_status = RPC_SYSTEMERROR;
2608                 e->call_reason = ENOSR;
2609                 return (FALSE);
2610         }
2611 



2612         mp->b_datap->db_type = M_PROTO;
2613         tcr = (struct T_conn_req *)mp->b_rptr;
2614         bzero(tcr, sizeof (*tcr));
2615         tcr->PRIM_type = T_CONN_REQ;
2616         tcr->DEST_length = addr->len;
2617         tcr->DEST_offset = sizeof (struct T_conn_req);
2618         mp->b_wptr = mp->b_rptr + sizeof (*tcr);
2619 
2620         bcopy(addr->buf, mp->b_wptr, tcr->DEST_length);
2621         mp->b_wptr += tcr->DEST_length;
2622 
2623         RPCLOG(8, "connmgr_connect: sending conn request on queue "
2624             "%p", (void *)wq);
2625         RPCLOG(8, " call %p\n", (void *)wq);
2626         /*
2627          * We use the entry in the handle that is normally used for
2628          * waiting for RPC replies to wait for the connection accept.
2629          */
2630         if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) {
2631                 DTRACE_PROBE(krpc__e__connmgr__connect__cantsend);


2747         }
2748 
2749         cm_entry->x_ksp->ks_lock = &connmgr_lock;
2750         cm_entry->x_ksp->ks_private = cm_entry;
2751         cm_entry->x_ksp->ks_data_size = ((INET6_ADDRSTRLEN * sizeof (char))
2752             + sizeof (cm_kstat_template));
2753         cm_entry->x_ksp->ks_data = kmem_alloc(cm_entry->x_ksp->ks_data_size,
2754             KM_SLEEP);
2755         bcopy(&cm_kstat_template, cm_entry->x_ksp->ks_data,
2756             cm_entry->x_ksp->ks_data_size);
2757         ((struct cm_kstat_xprt *)(cm_entry->x_ksp->ks_data))->
2758             x_server.value.str.addr.ptr =
2759             kmem_alloc(INET6_ADDRSTRLEN, KM_SLEEP);
2760 
2761         cm_entry->x_ksp->ks_update = conn_kstat_update;
2762         kstat_install(cm_entry->x_ksp);
2763         return (TRUE);
2764 }
2765 
2766 /*


















































































































2767  * Called by connmgr_connect to set an option on the new stream.
2768  */
2769 static bool_t
2770 connmgr_setopt(queue_t *wq, int level, int name, calllist_t *e, cred_t *cr)

2771 {
2772         mblk_t *mp;
2773         struct opthdr *opt;
2774         struct T_optmgmt_req *tor;
2775         struct timeval waitp;
2776         int error;
2777 
2778         mp = allocb_cred(sizeof (struct T_optmgmt_req) +
2779             sizeof (struct opthdr) + sizeof (int), cr, NOPID);
2780         if (mp == NULL) {
2781                 RPCLOG0(1, "connmgr_setopt: cannot alloc mp for option "
2782                     "request\n");
2783                 return (FALSE);
2784         }
2785 
2786         mp->b_datap->db_type = M_PROTO;
2787         tor = (struct T_optmgmt_req *)(mp->b_rptr);
2788         tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
2789         tor->MGMT_flags = T_NEGOTIATE;
2790         tor->OPT_length = sizeof (struct opthdr) + sizeof (int);
2791         tor->OPT_offset = sizeof (struct T_optmgmt_req);
2792 
2793         opt = (struct opthdr *)(mp->b_rptr + sizeof (struct T_optmgmt_req));
2794         opt->level = level;
2795         opt->name = name;
2796         opt->len = sizeof (int);
2797         *(int *)((char *)opt + sizeof (*opt)) = 1;
2798         mp->b_wptr += sizeof (struct T_optmgmt_req) + sizeof (struct opthdr) +
2799             sizeof (int);
2800 
2801         /*
2802          * We will use this connection regardless
2803          * of whether or not the option is settable.
2804          */
2805         if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) {
2806                 DTRACE_PROBE(krpc__e__connmgr__setopt__cantsend);
2807                 freemsg(mp);
2808                 return (FALSE);
2809         }
2810 
2811         mutex_enter(&clnt_pending_lock);
2812 
2813         waitp.tv_sec = clnt_cots_min_conntout;
2814         waitp.tv_usec = 0;
2815         error = waitforack(e, T_OPTMGMT_ACK, &waitp, 1);
2816 
2817         if (e->call_prev)
2818                 e->call_prev->call_next = e->call_next;
2819         else
2820                 clnt_pending = e->call_next;
2821         if (e->call_next)
2822                 e->call_next->call_prev = e->call_prev;
2823         mutex_exit(&clnt_pending_lock);
2824 
2825         if (e->call_reply != NULL) {
2826                 freemsg(e->call_reply);
2827                 e->call_reply = NULL;
2828         }
2829 
2830         if (e->call_status != RPC_SUCCESS || error != 0) {
2831                 RPCLOG(1, "connmgr_setopt: can't set option: %d\n", name);
2832                 return (FALSE);
2833         }
2834         RPCLOG(8, "connmgr_setopt: successfully set option: %d\n", name);
2835         return (TRUE);
2836 }
2837 






2838 #ifdef  DEBUG
2839 
2840 /*
2841  * This is a knob to let us force code coverage in allocation failure
2842  * case.
2843  */
2844 static int      connmgr_failsnd;
2845 #define CONN_SND_ALLOC(Size, Pri)       \
2846         ((connmgr_failsnd-- > 0) ? NULL : allocb(Size, Pri))
2847 
2848 #else
2849 
2850 #define CONN_SND_ALLOC(Size, Pri)       allocb(Size, Pri)
2851 
2852 #endif
2853 
2854 /*
2855  * Sends an orderly release on the specified queue.
2856  * Entered with connmgr_lock. Exited without connmgr_lock
2857  */




 173 #include <sys/systm.h>
 174 #include <sys/kstat.h>
 175 #include <sys/t_lock.h>
 176 #include <sys/ddi.h>
 177 #include <sys/cmn_err.h>
 178 #include <sys/time.h>
 179 #include <sys/isa_defs.h>
 180 #include <sys/callb.h>
 181 #include <sys/sunddi.h>
 182 #include <sys/atomic.h>
 183 #include <sys/sdt.h>
 184 
 185 #include <netinet/in.h>
 186 #include <netinet/tcp.h>
 187 
 188 #include <rpc/types.h>
 189 #include <rpc/xdr.h>
 190 #include <rpc/auth.h>
 191 #include <rpc/clnt.h>
 192 #include <rpc/rpc_msg.h>
 193 #include <nfs/nfs.h>
 194 
 195 #define COTS_DEFAULT_ALLOCSIZE  2048
 196 
 197 #define WIRE_HDR_SIZE   20      /* serialized call header, sans proc number */
 198 #define MSG_OFFSET      128     /* offset of call into the mblk */
 199 
 200 const char *kinet_ntop6(uchar_t *, char *, size_t);
 201 
 202 static int      clnt_cots_ksettimers(CLIENT *, struct rpc_timers *,
 203     struct rpc_timers *, int, void(*)(int, int, caddr_t), caddr_t, uint32_t);
 204 static enum clnt_stat   clnt_cots_kcallit(CLIENT *, rpcproc_t, xdrproc_t,
 205     caddr_t, xdrproc_t, caddr_t, struct timeval);
 206 static void     clnt_cots_kabort(CLIENT *);
 207 static void     clnt_cots_kerror(CLIENT *, struct rpc_err *);
 208 static bool_t   clnt_cots_kfreeres(CLIENT *, xdrproc_t, caddr_t);
 209 static void     clnt_cots_kdestroy(CLIENT *);
 210 static bool_t   clnt_cots_kcontrol(CLIENT *, int, char *);
 211 
 212 
 213 /* List of transports managed by the connection manager. */


 365         XDR                     cku_inxdr;      /* xdr routine for input */
 366         char                    cku_rpchdr[WIRE_HDR_SIZE + 4];
 367                                                 /* pre-serialized rpc header */
 368 
 369         uint_t                  cku_outbuflen;  /* default output mblk length */
 370         struct cred             *cku_cred;      /* credentials */
 371         bool_t                  cku_nodelayonerr;
 372                                                 /* for CLSET_NODELAYONERR */
 373         int                     cku_useresvport; /* Use reserved port */
 374         struct rpc_cots_client  *cku_stats;     /* stats for zone */
 375 } cku_private_t;
 376 
 377 static struct cm_xprt *connmgr_wrapconnect(struct cm_xprt *,
 378         const struct timeval *, struct netbuf *, int, struct netbuf *,
 379         struct rpc_err *, bool_t, bool_t, cred_t *);
 380 
 381 static bool_t   connmgr_connect(struct cm_xprt *, queue_t *, struct netbuf *,
 382                                 int, calllist_t *, int *, bool_t reconnect,
 383                                 const struct timeval *, bool_t, cred_t *);
 384 
 385 static bool_t  connmgr_getopt_int(queue_t *wq, int level, int name, int *val,
 386                                 calllist_t *e, cred_t *cr);
 387 static bool_t   connmgr_setopt_int(queue_t *, int, int, int,
 388                                 calllist_t *, cred_t *cr);
 389 static bool_t   connmgr_setopt(queue_t *, int, int, calllist_t *, cred_t *cr);
 390 static void     connmgr_sndrel(struct cm_xprt *);
 391 static void     connmgr_snddis(struct cm_xprt *);
 392 static void     connmgr_close(struct cm_xprt *);
 393 static void     connmgr_release(struct cm_xprt *);
 394 static struct cm_xprt *connmgr_wrapget(struct netbuf *, const struct timeval *,
 395         cku_private_t *);
 396 
 397 static struct cm_xprt *connmgr_get(struct netbuf *, const struct timeval *,
 398         struct netbuf *, int, struct netbuf *, struct rpc_err *, dev_t,
 399         bool_t, int, cred_t *);
 400 
 401 static void connmgr_cancelconn(struct cm_xprt *);
 402 static enum clnt_stat connmgr_cwait(struct cm_xprt *, const struct timeval *,
 403         bool_t);
 404 static void connmgr_dis_and_wait(struct cm_xprt *);
 405 
 406 static int      clnt_dispatch_send(queue_t *, mblk_t *, calllist_t *, uint_t,
 407                                         uint_t);
 408 


 490 #define htop(h)         ((cku_private_t *)((h)->cl_private))
 491 
 492 /*
 493  * Times to retry
 494  */
 495 #define REFRESHES       2       /* authentication refreshes */
 496 
 497 /*
 498  * The following is used to determine the global default behavior for
 499  * COTS when binding to a local port.
 500  *
 501  * If the value is set to 1 the default will be to select a reserved
 502  * (aka privileged) port, if the value is zero the default will be to
 503  * use non-reserved ports.  Users of kRPC may override this by using
 504  * CLNT_CONTROL() and CLSET_BINDRESVPORT.
 505  */
 506 int clnt_cots_do_bindresvport = 1;
 507 
 508 static zone_key_t zone_cots_key;
 509 
 510 #define TWO_GIGB        0x80000000
 511 int nfsd_port = NFS_PORT;
 512 /*
 513  * Defaults TCP send and receive buffer size for NFS connections.
 514  * These values can be tuned by /etc/default.
 515  */
 516 int nfs_send_bufsz = 1024*1024;
 517 int nfs_recv_bufsz = 1024*1024;
 518 /*
 519  * To use system-wide default for TCP send and receive buffer size,
 520  * use /etc/system to set nfs_default_bufsz to 1:
 521  *
 522  * set rpcmod:nfs_default_bufsz=1
 523  */
 524 int nfs_default_bufsz = 0;
 525 
 526 /*
 527  * We need to do this after all kernel threads in the zone have exited.
 528  */
 529 /* ARGSUSED */
 530 static void
 531 clnt_zone_destroy(zoneid_t zoneid, void *unused)
 532 {
 533         struct cm_xprt **cmp;
 534         struct cm_xprt *cm_entry;
 535         struct cm_xprt *freelist = NULL;
 536 
 537         mutex_enter(&connmgr_lock);
 538         cmp = &cm_hd;
 539         while ((cm_entry = *cmp) != NULL) {
 540                 if (cm_entry->x_zoneid == zoneid) {
 541                         *cmp = cm_entry->x_next;
 542                         cm_entry->x_next = freelist;
 543                         freelist = cm_entry;
 544                 } else {
 545                         cmp = &cm_entry->x_next;
 546                 }


2562         if (cm_entry->x_src.buf != NULL)
2563                 kmem_free(cm_entry->x_src.buf, cm_entry->x_src.maxlen);
2564         kmem_free(cm_entry, sizeof (struct cm_xprt));
2565 }
2566 
2567 /*
2568  * Called by KRPC after sending the call message to release the connection
2569  * it was using.
2570  */
2571 static void
2572 connmgr_release(struct cm_xprt *cm_entry)
2573 {
2574         mutex_enter(&cm_entry->x_lock);
2575         cm_entry->x_ref--;
2576         if (cm_entry->x_ref == 0)
2577                 cv_signal(&cm_entry->x_cv);
2578         mutex_exit(&cm_entry->x_lock);
2579 }
2580 
2581 /*
2582  * Set TCP receive and xmit buffer size for NFS connections.
2583  */
2584 static bool_t
2585 connmgr_nfs_setbufsz(calllist_t *e, int addrfmly, struct netbuf *addr,
2586     queue_t *wq, cred_t *cr)
2587 {
2588         struct sockaddr_in *sa;
2589         int ok = FALSE;
2590         int val;
2591         uint32_t sbufsz, rbufsz;
2592 
2593         if (nfs_default_bufsz ||
2594             (addrfmly != AF_INET && addrfmly != AF_INET6))
2595                 return (FALSE);
2596 
2597         sa = (struct sockaddr_in *)addr->buf;
2598         if (ntohs(sa->sin_port) != nfsd_port)
2599                 return (FALSE);
2600         /*
2601          * For system with 2GB, or less, of physical memory set send
2602          * and receive buffer size to half of nfs_send_bufsz and
2603          * nfs_recv_bufsz respectively.
2604          */
2605         if (ptob(physmem) <= TWO_GIGB) {
2606                 sbufsz = nfs_send_bufsz >> 1;
2607                 rbufsz = nfs_recv_bufsz >> 1;
2608         } else {
2609                 sbufsz = nfs_send_bufsz;
2610                 rbufsz = nfs_recv_bufsz;
2611         }
2612         /*
2613          * Only set new buffer size if it's larger than the system
2614          * default buffer size. If smaller buffer size is needed
2615          * then use /etc/system to set nfs_default_bufsz to 1.
2616          */
2617         ok = connmgr_getopt_int(wq, SOL_SOCKET, SO_RCVBUF, &val, e, cr);
2618         if ((ok == TRUE) && (val < sbufsz)) {
2619                 ok = connmgr_setopt_int(wq, SOL_SOCKET, SO_RCVBUF,
2620                     sbufsz, e, cr);
2621                 DTRACE_PROBE2(connmgr_nfs_rcvbufsz__setopt,
2622                     int, ok, calllist_t *, e);
2623         }
2624 
2625         ok = connmgr_getopt_int(wq, SOL_SOCKET, SO_SNDBUF, &val, e, cr);
2626         if ((ok == TRUE) && (val < rbufsz)) {
2627                 ok = connmgr_setopt_int(wq, SOL_SOCKET, SO_SNDBUF,
2628                     rbufsz, e, cr);
2629                 DTRACE_PROBE2(connmgr_nfs_sndbufsz__setopt,
2630                     int, ok, calllist_t *, e);
2631         }
2632         return (TRUE);
2633 }
2634 
2635 /*
2636  * Given an open stream, connect to the remote.  Returns true if connected,
2637  * false otherwise.
2638  */
2639 static bool_t
2640 connmgr_connect(
2641         struct cm_xprt          *cm_entry,
2642         queue_t                 *wq,
2643         struct netbuf           *addr,
2644         int                     addrfmly,
2645         calllist_t              *e,
2646         int                     *tidu_ptr,
2647         bool_t                  reconnect,
2648         const struct timeval    *waitp,
2649         bool_t                  nosignal,
2650         cred_t                  *cr)
2651 {
2652         mblk_t *mp;
2653         struct T_conn_req *tcr;
2654         struct T_info_ack *tinfo;
2655         int interrupted, error;


2667         if (mp == NULL) {
2668                 /*
2669                  * This is unfortunate, but we need to look up the stats for
2670                  * this zone to increment the "memory allocation failed"
2671                  * counter.  curproc->p_zone is safe since we're initiating a
2672                  * connection and not in some strange streams context.
2673                  */
2674                 struct rpcstat *rpcstat;
2675 
2676                 rpcstat = zone_getspecific(rpcstat_zone_key, rpc_zone());
2677                 ASSERT(rpcstat != NULL);
2678 
2679                 RPCLOG0(1, "connmgr_connect: cannot alloc mp for "
2680                     "sending conn request\n");
2681                 COTSRCSTAT_INCR(rpcstat->rpc_cots_client, rcnomem);
2682                 e->call_status = RPC_SYSTEMERROR;
2683                 e->call_reason = ENOSR;
2684                 return (FALSE);
2685         }
2686 
2687         /* Set TCP buffer size for NFS connections if needed */
2688         (void) connmgr_nfs_setbufsz(e, addrfmly, addr, wq, cr);
2689 
2690         mp->b_datap->db_type = M_PROTO;
2691         tcr = (struct T_conn_req *)mp->b_rptr;
2692         bzero(tcr, sizeof (*tcr));
2693         tcr->PRIM_type = T_CONN_REQ;
2694         tcr->DEST_length = addr->len;
2695         tcr->DEST_offset = sizeof (struct T_conn_req);
2696         mp->b_wptr = mp->b_rptr + sizeof (*tcr);
2697 
2698         bcopy(addr->buf, mp->b_wptr, tcr->DEST_length);
2699         mp->b_wptr += tcr->DEST_length;
2700 
2701         RPCLOG(8, "connmgr_connect: sending conn request on queue "
2702             "%p", (void *)wq);
2703         RPCLOG(8, " call %p\n", (void *)wq);
2704         /*
2705          * We use the entry in the handle that is normally used for
2706          * waiting for RPC replies to wait for the connection accept.
2707          */
2708         if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) {
2709                 DTRACE_PROBE(krpc__e__connmgr__connect__cantsend);


2825         }
2826 
2827         cm_entry->x_ksp->ks_lock = &connmgr_lock;
2828         cm_entry->x_ksp->ks_private = cm_entry;
2829         cm_entry->x_ksp->ks_data_size = ((INET6_ADDRSTRLEN * sizeof (char))
2830             + sizeof (cm_kstat_template));
2831         cm_entry->x_ksp->ks_data = kmem_alloc(cm_entry->x_ksp->ks_data_size,
2832             KM_SLEEP);
2833         bcopy(&cm_kstat_template, cm_entry->x_ksp->ks_data,
2834             cm_entry->x_ksp->ks_data_size);
2835         ((struct cm_kstat_xprt *)(cm_entry->x_ksp->ks_data))->
2836             x_server.value.str.addr.ptr =
2837             kmem_alloc(INET6_ADDRSTRLEN, KM_SLEEP);
2838 
2839         cm_entry->x_ksp->ks_update = conn_kstat_update;
2840         kstat_install(cm_entry->x_ksp);
2841         return (TRUE);
2842 }
2843 
2844 /*
2845  * Verify that the specified offset falls within the mblk and
2846  * that the resulting pointer is aligned.
2847  * Returns NULL if not.
2848  *
2849  * code from fs/sockfs/socksubr.c
2850  */
2851 static void *
2852 connmgr_opt_getoff(mblk_t *mp, t_uscalar_t offset,
2853     t_uscalar_t length, uint_t align_size)
2854 {
2855         uintptr_t ptr1, ptr2;
2856 
2857         ASSERT(mp && mp->b_wptr >= mp->b_rptr);
2858         ptr1 = (uintptr_t)mp->b_rptr + offset;
2859         ptr2 = (uintptr_t)ptr1 + length;
2860         if (ptr1 < (uintptr_t)mp->b_rptr || ptr2 > (uintptr_t)mp->b_wptr) {
2861                 return (NULL);
2862         }
2863         if ((ptr1 & (align_size - 1)) != 0) {
2864                 return (NULL);
2865         }
2866         return ((void *)ptr1);
2867 }
2868 
2869 static bool_t
2870 connmgr_getopt_int(queue_t *wq, int level, int name, int *val,
2871     calllist_t *e, cred_t *cr)
2872 {
2873         mblk_t *mp;
2874         struct opthdr *opt, *opt_res;
2875         struct T_optmgmt_req *tor;
2876         struct T_optmgmt_ack *opt_ack;
2877         struct timeval waitp;
2878         int error;
2879 
2880         mp = allocb_cred(sizeof (struct T_optmgmt_req) +
2881             sizeof (struct opthdr) + sizeof (int), cr, NOPID);
2882         if (mp == NULL) {
2883                 RPCLOG0(1, "connmgr_getopt: cannot alloc mp for option "
2884                     "request\n");
2885                 return (FALSE);
2886         }
2887 
2888         mp->b_datap->db_type = M_PROTO;
2889         tor = (struct T_optmgmt_req *)(mp->b_rptr);
2890         tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
2891         tor->MGMT_flags = T_CURRENT;
2892         tor->OPT_length = sizeof (struct opthdr) + sizeof (int);
2893         tor->OPT_offset = sizeof (struct T_optmgmt_req);
2894 
2895         opt = (struct opthdr *)(mp->b_rptr + sizeof (struct T_optmgmt_req));
2896         opt->level = level;
2897         opt->name = name;
2898         opt->len = sizeof (int);
2899         mp->b_wptr += sizeof (struct T_optmgmt_req) + sizeof (struct opthdr) +
2900             sizeof (int);
2901 
2902         /*
2903          * We will use this connection regardless
2904          * of whether or not the option is readable.
2905          */
2906         if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) {
2907                 DTRACE_PROBE(krpc__e__connmgr__getopt__cantsend);
2908                 freemsg(mp);
2909                 return (FALSE);
2910         }
2911 
2912         mutex_enter(&clnt_pending_lock);
2913 
2914         waitp.tv_sec = clnt_cots_min_conntout;
2915         waitp.tv_usec = 0;
2916         error = waitforack(e, T_OPTMGMT_ACK, &waitp, 1);
2917 
2918         if (e->call_prev)
2919                 e->call_prev->call_next = e->call_next;
2920         else
2921                 clnt_pending = e->call_next;
2922         if (e->call_next)
2923                 e->call_next->call_prev = e->call_prev;
2924         mutex_exit(&clnt_pending_lock);
2925 
2926         /* get reply message */
2927         mp = e->call_reply;
2928         e->call_reply = NULL;
2929 
2930         if ((!mp) || (e->call_status != RPC_SUCCESS) || (error != 0)) {
2931 
2932                 DTRACE_PROBE4(connmgr_getopt__failed, int, name,
2933                     int, e->call_status, int, error, mblk_t *, mp);
2934 
2935                 if (mp)
2936                         freemsg(mp);
2937                 return (FALSE);
2938         }
2939 
2940         opt_ack = (struct T_optmgmt_ack *)mp->b_rptr;
2941         opt_res = (struct opthdr *)connmgr_opt_getoff(mp, opt_ack->OPT_offset,
2942             opt_ack->OPT_length, __TPI_ALIGN_SIZE);
2943 
2944         if (!opt_res) {
2945                 DTRACE_PROBE4(connmgr_getopt__optres, mblk_t *, mp, int, name,
2946                     int, opt_ack->OPT_offset, int, opt_ack->OPT_length);
2947                 freemsg(mp);
2948                 return (FALSE);
2949         }
2950         *val = *(int *)&opt_res[1];
2951 
2952         DTRACE_PROBE2(connmgr_getopt__ok, int, name, int, *val);
2953 
2954         freemsg(mp);
2955         return (TRUE);
2956 }
2957 
2958 /*
2959  * Called by connmgr_connect to set an option on the new stream.
2960  */
2961 static bool_t
2962 connmgr_setopt_int(queue_t *wq, int level, int name, int val,
2963     calllist_t *e, cred_t *cr)
2964 {
2965         mblk_t *mp;
2966         struct opthdr *opt;
2967         struct T_optmgmt_req *tor;
2968         struct timeval waitp;
2969         int error;
2970 
2971         mp = allocb_cred(sizeof (struct T_optmgmt_req) +
2972             sizeof (struct opthdr) + sizeof (int), cr, NOPID);
2973         if (mp == NULL) {
2974                 RPCLOG0(1, "connmgr_setopt: cannot alloc mp for option "
2975                     "request\n");
2976                 return (FALSE);
2977         }
2978 
2979         mp->b_datap->db_type = M_PROTO;
2980         tor = (struct T_optmgmt_req *)(mp->b_rptr);
2981         tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
2982         tor->MGMT_flags = T_NEGOTIATE;
2983         tor->OPT_length = sizeof (struct opthdr) + sizeof (int);
2984         tor->OPT_offset = sizeof (struct T_optmgmt_req);
2985 
2986         opt = (struct opthdr *)(mp->b_rptr + sizeof (struct T_optmgmt_req));
2987         opt->level = level;
2988         opt->name = name;
2989         opt->len = sizeof (int);
2990         *(int *)((char *)opt + sizeof (*opt)) = val;
2991         mp->b_wptr += sizeof (struct T_optmgmt_req) + sizeof (struct opthdr) +
2992             sizeof (int);
2993 
2994         /*
2995          * We will use this connection regardless
2996          * of whether or not the option is settable.
2997          */
2998         if (clnt_dispatch_send(wq, mp, e, 0, 0) != RPC_SUCCESS) {
2999                 DTRACE_PROBE(krpc__e__connmgr__setopt__cantsend);
3000                 freemsg(mp);
3001                 return (FALSE);
3002         }
3003 
3004         mutex_enter(&clnt_pending_lock);
3005 
3006         waitp.tv_sec = clnt_cots_min_conntout;
3007         waitp.tv_usec = 0;
3008         error = waitforack(e, T_OPTMGMT_ACK, &waitp, 1);
3009 
3010         if (e->call_prev)
3011                 e->call_prev->call_next = e->call_next;
3012         else
3013                 clnt_pending = e->call_next;
3014         if (e->call_next)
3015                 e->call_next->call_prev = e->call_prev;
3016         mutex_exit(&clnt_pending_lock);
3017 
3018         if (e->call_reply != NULL) {
3019                 freemsg(e->call_reply);
3020                 e->call_reply = NULL;
3021         }
3022 
3023         if (e->call_status != RPC_SUCCESS || error != 0) {
3024                 RPCLOG(1, "connmgr_setopt: can't set option: %d\n", name);
3025                 return (FALSE);
3026         }
3027         RPCLOG(8, "connmgr_setopt: successfully set option: %d\n", name);
3028         return (TRUE);
3029 }
3030 
3031 static bool_t
3032 connmgr_setopt(queue_t *wq, int level, int name, calllist_t *e, cred_t *cr)
3033 {
3034         return (connmgr_setopt_int(wq, level, name, 1, e, cr));
3035 }
3036 
3037 #ifdef  DEBUG
3038 
3039 /*
3040  * This is a knob to let us force code coverage in allocation failure
3041  * case.
3042  */
3043 static int      connmgr_failsnd;
3044 #define CONN_SND_ALLOC(Size, Pri)       \
3045         ((connmgr_failsnd-- > 0) ? NULL : allocb(Size, Pri))
3046 
3047 #else
3048 
3049 #define CONN_SND_ALLOC(Size, Pri)       allocb(Size, Pri)
3050 
3051 #endif
3052 
3053 /*
3054  * Sends an orderly release on the specified queue.
3055  * Entered with connmgr_lock. Exited without connmgr_lock
3056  */