17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5a26eed27Sgt29601 * Common Development and Distribution License (the "License").
6a26eed27Sgt29601 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22c242f9a0Schunli zhang - Sun Microsystems - Irvine United States * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
242695d4f4SMarcel Telka */
252695d4f4SMarcel Telka /*
26b97d6ca7SMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved.
272695d4f4SMarcel Telka * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
327c478bd9Sstevel@tonic-gate /* All Rights Reserved */
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate * Kernel RPC filtering module
367c478bd9Sstevel@tonic-gate */
377c478bd9Sstevel@tonic-gate
387c478bd9Sstevel@tonic-gate #include <sys/param.h>
397c478bd9Sstevel@tonic-gate #include <sys/types.h>
407c478bd9Sstevel@tonic-gate #include <sys/stream.h>
417c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
42de8c4a14SErik Nordmark #include <sys/strsubr.h>
437c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
447c478bd9Sstevel@tonic-gate #include <sys/timod.h>
457c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
467c478bd9Sstevel@tonic-gate #include <sys/debug.h>
477c478bd9Sstevel@tonic-gate #include <sys/signal.h>
487c478bd9Sstevel@tonic-gate #include <sys/pcb.h>
497c478bd9Sstevel@tonic-gate #include <sys/user.h>
507c478bd9Sstevel@tonic-gate #include <sys/errno.h>
517c478bd9Sstevel@tonic-gate #include <sys/cred.h>
527c478bd9Sstevel@tonic-gate #include <sys/policy.h>
537c478bd9Sstevel@tonic-gate #include <sys/inline.h>
547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
557c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
567c478bd9Sstevel@tonic-gate #include <sys/file.h>
577c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
587c478bd9Sstevel@tonic-gate #include <sys/systm.h>
597c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
607c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
617c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
627c478bd9Sstevel@tonic-gate #include <sys/callb.h>
63153adbb6Smeem #include <sys/strsun.h>
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
667c478bd9Sstevel@tonic-gate #include <rpc/rpc_com.h>
677c478bd9Sstevel@tonic-gate #include <inet/common.h>
687c478bd9Sstevel@tonic-gate #include <rpc/types.h>
697c478bd9Sstevel@tonic-gate #include <sys/time.h>
707c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
717c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
727c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
737c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.h>
747c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
757c478bd9Sstevel@tonic-gate #include <rpc/svc.h>
767c478bd9Sstevel@tonic-gate #include <rpc/rpcsys.h>
777c478bd9Sstevel@tonic-gate #include <rpc/rpc_rdma.h>
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate * This is the loadable module wrapper.
817c478bd9Sstevel@tonic-gate */
827c478bd9Sstevel@tonic-gate #include <sys/conf.h>
837c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
847c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate extern struct streamtab rpcinfo;
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate static struct fmodsw fsw = {
897c478bd9Sstevel@tonic-gate "rpcmod",
907c478bd9Sstevel@tonic-gate &rpcinfo,
917c478bd9Sstevel@tonic-gate D_NEW|D_MP,
927c478bd9Sstevel@tonic-gate };
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate * Module linkage information for the kernel.
967c478bd9Sstevel@tonic-gate */
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
997c478bd9Sstevel@tonic-gate &mod_strmodops, "rpc interface str mod", &fsw
1007c478bd9Sstevel@tonic-gate };
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate * For the RPC system call.
1047c478bd9Sstevel@tonic-gate */
1057c478bd9Sstevel@tonic-gate static struct sysent rpcsysent = {
1067c478bd9Sstevel@tonic-gate 2,
1077c478bd9Sstevel@tonic-gate SE_32RVAL1 | SE_ARGC | SE_NOUNLOAD,
1087c478bd9Sstevel@tonic-gate rpcsys
1097c478bd9Sstevel@tonic-gate };
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate static struct modlsys modlsys = {
1127c478bd9Sstevel@tonic-gate &mod_syscallops,
1137c478bd9Sstevel@tonic-gate "RPC syscall",
1147c478bd9Sstevel@tonic-gate &rpcsysent
1157c478bd9Sstevel@tonic-gate };
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1187c478bd9Sstevel@tonic-gate static struct modlsys modlsys32 = {
1197c478bd9Sstevel@tonic-gate &mod_syscallops32,
1207c478bd9Sstevel@tonic-gate "32-bit RPC syscall",
1217c478bd9Sstevel@tonic-gate &rpcsysent
1227c478bd9Sstevel@tonic-gate };
1237c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1267c478bd9Sstevel@tonic-gate MODREV_1,
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate &modlsys,
1297c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1307c478bd9Sstevel@tonic-gate &modlsys32,
1317c478bd9Sstevel@tonic-gate #endif
1327c478bd9Sstevel@tonic-gate &modlstrmod,
1337c478bd9Sstevel@tonic-gate NULL
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate };
1367c478bd9Sstevel@tonic-gate
1377c478bd9Sstevel@tonic-gate int
_init(void)1387c478bd9Sstevel@tonic-gate _init(void)
1397c478bd9Sstevel@tonic-gate {
1407c478bd9Sstevel@tonic-gate int error = 0;
1417c478bd9Sstevel@tonic-gate callb_id_t cid;
1427c478bd9Sstevel@tonic-gate int status;
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate svc_init();
1457c478bd9Sstevel@tonic-gate clnt_init();
1467c478bd9Sstevel@tonic-gate cid = callb_add(connmgr_cpr_reset, 0, CB_CL_CPR_RPC, "rpc");
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate if (error = mod_install(&modlinkage)) {
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate * Could not install module, cleanup previous
1517c478bd9Sstevel@tonic-gate * initialization work.
1527c478bd9Sstevel@tonic-gate */
1537c478bd9Sstevel@tonic-gate clnt_fini();
1547c478bd9Sstevel@tonic-gate if (cid != NULL)
1557c478bd9Sstevel@tonic-gate (void) callb_delete(cid);
1567c478bd9Sstevel@tonic-gate
1577c478bd9Sstevel@tonic-gate return (error);
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate /*
1617c478bd9Sstevel@tonic-gate * Load up the RDMA plugins and initialize the stats. Even if the
1627c478bd9Sstevel@tonic-gate * plugins loadup fails, but rpcmod was successfully installed the
1637c478bd9Sstevel@tonic-gate * counters still get initialized.
1647c478bd9Sstevel@tonic-gate */
1657c478bd9Sstevel@tonic-gate rw_init(&rdma_lock, NULL, RW_DEFAULT, NULL);
1667c478bd9Sstevel@tonic-gate mutex_init(&rdma_modload_lock, NULL, MUTEX_DEFAULT, NULL);
16751f34d4bSRajkumar Sivaprakasam
16851f34d4bSRajkumar Sivaprakasam cv_init(&rdma_wait.svc_cv, NULL, CV_DEFAULT, NULL);
16951f34d4bSRajkumar Sivaprakasam mutex_init(&rdma_wait.svc_lock, NULL, MUTEX_DEFAULT, NULL);
17051f34d4bSRajkumar Sivaprakasam
1717c478bd9Sstevel@tonic-gate mt_kstat_init();
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate /*
1747c478bd9Sstevel@tonic-gate * Get our identification into ldi. This is used for loading
1757c478bd9Sstevel@tonic-gate * other modules, e.g. rpcib.
1767c478bd9Sstevel@tonic-gate */
1777c478bd9Sstevel@tonic-gate status = ldi_ident_from_mod(&modlinkage, &rpcmod_li);
1787c478bd9Sstevel@tonic-gate if (status != 0) {
1797c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "ldi_ident_from_mod fails with %d", status);
1807c478bd9Sstevel@tonic-gate rpcmod_li = NULL;
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate return (error);
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate /*
1877c478bd9Sstevel@tonic-gate * The unload entry point fails, because we advertise entry points into
1887c478bd9Sstevel@tonic-gate * rpcmod from the rest of kRPC: rpcmod_release().
1897c478bd9Sstevel@tonic-gate */
1907c478bd9Sstevel@tonic-gate int
_fini(void)1917c478bd9Sstevel@tonic-gate _fini(void)
1927c478bd9Sstevel@tonic-gate {
1937c478bd9Sstevel@tonic-gate return (EBUSY);
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1977c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate extern int nulldev();
2037c478bd9Sstevel@tonic-gate
2047c478bd9Sstevel@tonic-gate #define RPCMOD_ID 2049
2057c478bd9Sstevel@tonic-gate
206b97d6ca7SMilan Jurik int rmm_open(queue_t *, dev_t *, int, int, cred_t *);
207b97d6ca7SMilan Jurik int rmm_close(queue_t *, int, cred_t *);
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate * To save instructions, since STREAMS ignores the return value
2117c478bd9Sstevel@tonic-gate * from these functions, they are defined as void here. Kind of icky, but...
2127c478bd9Sstevel@tonic-gate */
2137c478bd9Sstevel@tonic-gate void rmm_rput(queue_t *, mblk_t *);
2147c478bd9Sstevel@tonic-gate void rmm_wput(queue_t *, mblk_t *);
2157c478bd9Sstevel@tonic-gate void rmm_rsrv(queue_t *);
2167c478bd9Sstevel@tonic-gate void rmm_wsrv(queue_t *);
2177c478bd9Sstevel@tonic-gate
218b97d6ca7SMilan Jurik int rpcmodopen(queue_t *, dev_t *, int, int, cred_t *);
219b97d6ca7SMilan Jurik int rpcmodclose(queue_t *, int, cred_t *);
220b97d6ca7SMilan Jurik void rpcmodrput(queue_t *, mblk_t *);
221b97d6ca7SMilan Jurik void rpcmodwput(queue_t *, mblk_t *);
222b97d6ca7SMilan Jurik void rpcmodrsrv();
223b97d6ca7SMilan Jurik void rpcmodwsrv(queue_t *);
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate static void rpcmodwput_other(queue_t *, mblk_t *);
2267c478bd9Sstevel@tonic-gate static int mir_close(queue_t *q);
2277c478bd9Sstevel@tonic-gate static int mir_open(queue_t *q, dev_t *devp, int flag, int sflag,
2287c478bd9Sstevel@tonic-gate cred_t *credp);
2297c478bd9Sstevel@tonic-gate static void mir_rput(queue_t *q, mblk_t *mp);
2307c478bd9Sstevel@tonic-gate static void mir_rsrv(queue_t *q);
2317c478bd9Sstevel@tonic-gate static void mir_wput(queue_t *q, mblk_t *mp);
2327c478bd9Sstevel@tonic-gate static void mir_wsrv(queue_t *q);
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate static struct module_info rpcmod_info =
2357c478bd9Sstevel@tonic-gate {RPCMOD_ID, "rpcmod", 0, INFPSZ, 256*1024, 1024};
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate static struct qinit rpcmodrinit = {
2387c478bd9Sstevel@tonic-gate (int (*)())rmm_rput,
2397c478bd9Sstevel@tonic-gate (int (*)())rmm_rsrv,
2407c478bd9Sstevel@tonic-gate rmm_open,
2417c478bd9Sstevel@tonic-gate rmm_close,
2427c478bd9Sstevel@tonic-gate nulldev,
2437c478bd9Sstevel@tonic-gate &rpcmod_info,
2447c478bd9Sstevel@tonic-gate NULL
2457c478bd9Sstevel@tonic-gate };
2467c478bd9Sstevel@tonic-gate
2477c478bd9Sstevel@tonic-gate /*
2487c478bd9Sstevel@tonic-gate * The write put procedure is simply putnext to conserve stack space.
2497c478bd9Sstevel@tonic-gate * The write service procedure is not used to queue data, but instead to
2507c478bd9Sstevel@tonic-gate * synchronize with flow control.
2517c478bd9Sstevel@tonic-gate */
2527c478bd9Sstevel@tonic-gate static struct qinit rpcmodwinit = {
2537c478bd9Sstevel@tonic-gate (int (*)())rmm_wput,
2547c478bd9Sstevel@tonic-gate (int (*)())rmm_wsrv,
2557c478bd9Sstevel@tonic-gate rmm_open,
2567c478bd9Sstevel@tonic-gate rmm_close,
2577c478bd9Sstevel@tonic-gate nulldev,
2587c478bd9Sstevel@tonic-gate &rpcmod_info,
2597c478bd9Sstevel@tonic-gate NULL
2607c478bd9Sstevel@tonic-gate };
2617c478bd9Sstevel@tonic-gate struct streamtab rpcinfo = { &rpcmodrinit, &rpcmodwinit, NULL, NULL };
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate struct xprt_style_ops {
2647c478bd9Sstevel@tonic-gate int (*xo_open)();
2657c478bd9Sstevel@tonic-gate int (*xo_close)();
2667c478bd9Sstevel@tonic-gate void (*xo_wput)();
2677c478bd9Sstevel@tonic-gate void (*xo_wsrv)();
2687c478bd9Sstevel@tonic-gate void (*xo_rput)();
2697c478bd9Sstevel@tonic-gate void (*xo_rsrv)();
2707c478bd9Sstevel@tonic-gate };
2717c478bd9Sstevel@tonic-gate
2722695d4f4SMarcel Telka /*
2732695d4f4SMarcel Telka * Read side has no service procedure.
2742695d4f4SMarcel Telka */
2757c478bd9Sstevel@tonic-gate static struct xprt_style_ops xprt_clts_ops = {
2767c478bd9Sstevel@tonic-gate rpcmodopen,
2777c478bd9Sstevel@tonic-gate rpcmodclose,
2787c478bd9Sstevel@tonic-gate rpcmodwput,
2797c478bd9Sstevel@tonic-gate rpcmodwsrv,
2807c478bd9Sstevel@tonic-gate rpcmodrput,
2817c478bd9Sstevel@tonic-gate NULL
2827c478bd9Sstevel@tonic-gate };
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate static struct xprt_style_ops xprt_cots_ops = {
2857c478bd9Sstevel@tonic-gate mir_open,
2867c478bd9Sstevel@tonic-gate mir_close,
2877c478bd9Sstevel@tonic-gate mir_wput,
2887c478bd9Sstevel@tonic-gate mir_wsrv,
2897c478bd9Sstevel@tonic-gate mir_rput,
2907c478bd9Sstevel@tonic-gate mir_rsrv
2917c478bd9Sstevel@tonic-gate };
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate /*
2947c478bd9Sstevel@tonic-gate * Per rpcmod "slot" data structure. q->q_ptr points to one of these.
2957c478bd9Sstevel@tonic-gate */
2967c478bd9Sstevel@tonic-gate struct rpcm {
2972695d4f4SMarcel Telka void *rm_krpc_cell; /* Reserved for use by kRPC */
2987c478bd9Sstevel@tonic-gate struct xprt_style_ops *rm_ops;
2997c478bd9Sstevel@tonic-gate int rm_type; /* Client or server side stream */
3007c478bd9Sstevel@tonic-gate #define RM_CLOSING 0x1 /* somebody is trying to close slot */
3017c478bd9Sstevel@tonic-gate uint_t rm_state; /* state of the slot. see above */
3027c478bd9Sstevel@tonic-gate uint_t rm_ref; /* cnt of external references to slot */
3037c478bd9Sstevel@tonic-gate kmutex_t rm_lock; /* mutex protecting above fields */
3047c478bd9Sstevel@tonic-gate kcondvar_t rm_cwait; /* condition for closing */
3057c478bd9Sstevel@tonic-gate zoneid_t rm_zoneid; /* zone which pushed rpcmod */
3067c478bd9Sstevel@tonic-gate };
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate struct temp_slot {
3097c478bd9Sstevel@tonic-gate void *cell;
3107c478bd9Sstevel@tonic-gate struct xprt_style_ops *ops;
3117c478bd9Sstevel@tonic-gate int type;
3127c478bd9Sstevel@tonic-gate mblk_t *info_ack;
3137c478bd9Sstevel@tonic-gate kmutex_t lock;
3147c478bd9Sstevel@tonic-gate kcondvar_t wait;
3157c478bd9Sstevel@tonic-gate };
3167c478bd9Sstevel@tonic-gate
317fcfe7086Sgeorges typedef struct mir_s {
3182695d4f4SMarcel Telka void *mir_krpc_cell; /* Reserved for kRPC use. This field */
319fcfe7086Sgeorges /* must be first in the structure. */
320fcfe7086Sgeorges struct xprt_style_ops *rm_ops;
321fcfe7086Sgeorges int mir_type; /* Client or server side stream */
322fcfe7086Sgeorges
323fcfe7086Sgeorges mblk_t *mir_head_mp; /* RPC msg in progress */
324fcfe7086Sgeorges /*
325fcfe7086Sgeorges * mir_head_mp points the first mblk being collected in
326fcfe7086Sgeorges * the current RPC message. Record headers are removed
327fcfe7086Sgeorges * before data is linked into mir_head_mp.
328fcfe7086Sgeorges */
329fcfe7086Sgeorges mblk_t *mir_tail_mp; /* Last mblk in mir_head_mp */
330fcfe7086Sgeorges /*
331fcfe7086Sgeorges * mir_tail_mp points to the last mblk in the message
332fcfe7086Sgeorges * chain starting at mir_head_mp. It is only valid
333fcfe7086Sgeorges * if mir_head_mp is non-NULL and is used to add new
334fcfe7086Sgeorges * data blocks to the end of chain quickly.
335fcfe7086Sgeorges */
336fcfe7086Sgeorges
337fcfe7086Sgeorges int32_t mir_frag_len; /* Bytes seen in the current frag */
338fcfe7086Sgeorges /*
339fcfe7086Sgeorges * mir_frag_len starts at -4 for beginning of each fragment.
340fcfe7086Sgeorges * When this length is negative, it indicates the number of
341fcfe7086Sgeorges * bytes that rpcmod needs to complete the record marker
342fcfe7086Sgeorges * header. When it is positive or zero, it holds the number
343fcfe7086Sgeorges * of bytes that have arrived for the current fragment and
344fcfe7086Sgeorges * are held in mir_header_mp.
345fcfe7086Sgeorges */
346fcfe7086Sgeorges
347fcfe7086Sgeorges int32_t mir_frag_header;
348fcfe7086Sgeorges /*
349fcfe7086Sgeorges * Fragment header as collected for the current fragment.
350fcfe7086Sgeorges * It holds the last-fragment indicator and the number
351fcfe7086Sgeorges * of bytes in the fragment.
352fcfe7086Sgeorges */
353fcfe7086Sgeorges
354fcfe7086Sgeorges unsigned int
355fcfe7086Sgeorges mir_ordrel_pending : 1, /* Sent T_ORDREL_REQ */
356fcfe7086Sgeorges mir_hold_inbound : 1, /* Hold inbound messages on server */
357fcfe7086Sgeorges /* side until outbound flow control */
358fcfe7086Sgeorges /* is relieved. */
359fcfe7086Sgeorges mir_closing : 1, /* The stream is being closed */
360fcfe7086Sgeorges mir_inrservice : 1, /* data queued or rd srv proc running */
361fcfe7086Sgeorges mir_inwservice : 1, /* data queued or wr srv proc running */
362fcfe7086Sgeorges mir_inwflushdata : 1, /* flush M_DATAs when srv runs */
363fcfe7086Sgeorges /*
364fcfe7086Sgeorges * On client streams, mir_clntreq is 0 or 1; it is set
365fcfe7086Sgeorges * to 1 whenever a new request is sent out (mir_wput)
366fcfe7086Sgeorges * and cleared when the timer fires (mir_timer). If
367fcfe7086Sgeorges * the timer fires with this value equal to 0, then the
3682695d4f4SMarcel Telka * stream is considered idle and kRPC is notified.
369fcfe7086Sgeorges */
370fcfe7086Sgeorges mir_clntreq : 1,
371fcfe7086Sgeorges /*
372fcfe7086Sgeorges * On server streams, stop accepting messages
373fcfe7086Sgeorges */
374fcfe7086Sgeorges mir_svc_no_more_msgs : 1,
375fcfe7086Sgeorges mir_listen_stream : 1, /* listen end point */
376fcfe7086Sgeorges mir_unused : 1, /* no longer used */
377fcfe7086Sgeorges mir_timer_call : 1,
378fcfe7086Sgeorges mir_junk_fill_thru_bit_31 : 21;
379fcfe7086Sgeorges
380fcfe7086Sgeorges int mir_setup_complete; /* server has initialized everything */
381fcfe7086Sgeorges timeout_id_t mir_timer_id; /* Timer for idle checks */
382fcfe7086Sgeorges clock_t mir_idle_timeout; /* Allowed idle time before shutdown */
383fcfe7086Sgeorges /*
384fcfe7086Sgeorges * This value is copied from clnt_idle_timeout or
385fcfe7086Sgeorges * svc_idle_timeout during the appropriate ioctl.
386fcfe7086Sgeorges * Kept in milliseconds
387fcfe7086Sgeorges */
388fcfe7086Sgeorges clock_t mir_use_timestamp; /* updated on client with each use */
389fcfe7086Sgeorges /*
390fcfe7086Sgeorges * This value is set to lbolt
391fcfe7086Sgeorges * every time a client stream sends or receives data.
392fcfe7086Sgeorges * Even if the timer message arrives, we don't shutdown
393fcfe7086Sgeorges * client unless:
394fcfe7086Sgeorges * lbolt >= MSEC_TO_TICK(mir_idle_timeout)+mir_use_timestamp.
395fcfe7086Sgeorges * This value is kept in HZ.
396fcfe7086Sgeorges */
397fcfe7086Sgeorges
398fcfe7086Sgeorges uint_t *mir_max_msg_sizep; /* Reference to sanity check size */
399fcfe7086Sgeorges /*
400fcfe7086Sgeorges * This pointer is set to &clnt_max_msg_size or
401fcfe7086Sgeorges * &svc_max_msg_size during the appropriate ioctl.
402fcfe7086Sgeorges */
403fcfe7086Sgeorges zoneid_t mir_zoneid; /* zone which pushed rpcmod */
404fcfe7086Sgeorges /* Server-side fields. */
405fcfe7086Sgeorges int mir_ref_cnt; /* Reference count: server side only */
406fcfe7086Sgeorges /* counts the number of references */
407fcfe7086Sgeorges /* that a kernel RPC server thread */
408fcfe7086Sgeorges /* (see svc_run()) has on this rpcmod */
409fcfe7086Sgeorges /* slot. Effectively, it is the */
4102695d4f4SMarcel Telka /* number of unprocessed messages */
411fcfe7086Sgeorges /* that have been passed up to the */
4122695d4f4SMarcel Telka /* kRPC layer */
413fcfe7086Sgeorges
414fcfe7086Sgeorges mblk_t *mir_svc_pend_mp; /* Pending T_ORDREL_IND or */
415fcfe7086Sgeorges /* T_DISCON_IND */
416fcfe7086Sgeorges
417fcfe7086Sgeorges /*
418fcfe7086Sgeorges * these fields are for both client and server, but for debugging,
419fcfe7086Sgeorges * it is easier to have these last in the structure.
420fcfe7086Sgeorges */
421fcfe7086Sgeorges kmutex_t mir_mutex; /* Mutex and condvar for close */
422fcfe7086Sgeorges kcondvar_t mir_condvar; /* synchronization. */
423fcfe7086Sgeorges kcondvar_t mir_timer_cv; /* Timer routine sync. */
424fcfe7086Sgeorges } mir_t;
425fcfe7086Sgeorges
4267c478bd9Sstevel@tonic-gate void tmp_rput(queue_t *q, mblk_t *mp);
4277c478bd9Sstevel@tonic-gate
4287c478bd9Sstevel@tonic-gate struct xprt_style_ops tmpops = {
4297c478bd9Sstevel@tonic-gate NULL,
4307c478bd9Sstevel@tonic-gate NULL,
4317c478bd9Sstevel@tonic-gate putnext,
4327c478bd9Sstevel@tonic-gate NULL,
4337c478bd9Sstevel@tonic-gate tmp_rput,
4347c478bd9Sstevel@tonic-gate NULL
4357c478bd9Sstevel@tonic-gate };
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate void
tmp_rput(queue_t * q,mblk_t * mp)4387c478bd9Sstevel@tonic-gate tmp_rput(queue_t *q, mblk_t *mp)
4397c478bd9Sstevel@tonic-gate {
4407c478bd9Sstevel@tonic-gate struct temp_slot *t = (struct temp_slot *)(q->q_ptr);
4417c478bd9Sstevel@tonic-gate struct T_info_ack *pptr;
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
4447c478bd9Sstevel@tonic-gate case M_PCPROTO:
4457c478bd9Sstevel@tonic-gate pptr = (struct T_info_ack *)mp->b_rptr;
4467c478bd9Sstevel@tonic-gate switch (pptr->PRIM_type) {
4477c478bd9Sstevel@tonic-gate case T_INFO_ACK:
4487c478bd9Sstevel@tonic-gate mutex_enter(&t->lock);
4497c478bd9Sstevel@tonic-gate t->info_ack = mp;
4507c478bd9Sstevel@tonic-gate cv_signal(&t->wait);
4517c478bd9Sstevel@tonic-gate mutex_exit(&t->lock);
4527c478bd9Sstevel@tonic-gate return;
4537c478bd9Sstevel@tonic-gate default:
4547c478bd9Sstevel@tonic-gate break;
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate default:
4577c478bd9Sstevel@tonic-gate break;
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate /*
4617c478bd9Sstevel@tonic-gate * Not an info-ack, so free it. This is ok because we should
4627c478bd9Sstevel@tonic-gate * not be receiving data until the open finishes: rpcmod
4637c478bd9Sstevel@tonic-gate * is pushed well before the end-point is bound to an address.
4647c478bd9Sstevel@tonic-gate */
4657c478bd9Sstevel@tonic-gate freemsg(mp);
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate int
rmm_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * crp)4697c478bd9Sstevel@tonic-gate rmm_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
4707c478bd9Sstevel@tonic-gate {
4717c478bd9Sstevel@tonic-gate mblk_t *bp;
4727c478bd9Sstevel@tonic-gate struct temp_slot ts, *t;
4737c478bd9Sstevel@tonic-gate struct T_info_ack *pptr;
4747c478bd9Sstevel@tonic-gate int error = 0;
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate ASSERT(q != NULL);
4777c478bd9Sstevel@tonic-gate /*
4787c478bd9Sstevel@tonic-gate * Check for re-opens.
4797c478bd9Sstevel@tonic-gate */
4807c478bd9Sstevel@tonic-gate if (q->q_ptr) {
4817c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_KRPC, TR_RPCMODOPEN_END,
4827c478bd9Sstevel@tonic-gate "rpcmodopen_end:(%s)", "q->qptr");
4837c478bd9Sstevel@tonic-gate return (0);
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate t = &ts;
4877c478bd9Sstevel@tonic-gate bzero(t, sizeof (*t));
4887c478bd9Sstevel@tonic-gate q->q_ptr = (void *)t;
489fcfe7086Sgeorges WR(q)->q_ptr = (void *)t;
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate /*
4927c478bd9Sstevel@tonic-gate * Allocate the required messages upfront.
4937c478bd9Sstevel@tonic-gate */
494de8c4a14SErik Nordmark if ((bp = allocb_cred(sizeof (struct T_info_req) +
495de8c4a14SErik Nordmark sizeof (struct T_info_ack), crp, curproc->p_pid)) == NULL) {
4967c478bd9Sstevel@tonic-gate return (ENOBUFS);
4977c478bd9Sstevel@tonic-gate }
4987c478bd9Sstevel@tonic-gate
4997c478bd9Sstevel@tonic-gate mutex_init(&t->lock, NULL, MUTEX_DEFAULT, NULL);
5007c478bd9Sstevel@tonic-gate cv_init(&t->wait, NULL, CV_DEFAULT, NULL);
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate t->ops = &tmpops;
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate qprocson(q);
5057c478bd9Sstevel@tonic-gate bp->b_datap->db_type = M_PCPROTO;
5067c478bd9Sstevel@tonic-gate *(int32_t *)bp->b_wptr = (int32_t)T_INFO_REQ;
5077c478bd9Sstevel@tonic-gate bp->b_wptr += sizeof (struct T_info_req);
5087c478bd9Sstevel@tonic-gate putnext(WR(q), bp);
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate mutex_enter(&t->lock);
511fcfe7086Sgeorges while (t->info_ack == NULL) {
5127c478bd9Sstevel@tonic-gate if (cv_wait_sig(&t->wait, &t->lock) == 0) {
5137c478bd9Sstevel@tonic-gate error = EINTR;
5147c478bd9Sstevel@tonic-gate break;
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate mutex_exit(&t->lock);
518fcfe7086Sgeorges
5197c478bd9Sstevel@tonic-gate if (error)
5207c478bd9Sstevel@tonic-gate goto out;
5217c478bd9Sstevel@tonic-gate
5227c478bd9Sstevel@tonic-gate pptr = (struct T_info_ack *)t->info_ack->b_rptr;
5237c478bd9Sstevel@tonic-gate
5247c478bd9Sstevel@tonic-gate if (pptr->SERV_type == T_CLTS) {
525fcfe7086Sgeorges if ((error = rpcmodopen(q, devp, flag, sflag, crp)) == 0)
526fcfe7086Sgeorges ((struct rpcm *)q->q_ptr)->rm_ops = &xprt_clts_ops;
5277c478bd9Sstevel@tonic-gate } else {
528fcfe7086Sgeorges if ((error = mir_open(q, devp, flag, sflag, crp)) == 0)
529fcfe7086Sgeorges ((mir_t *)q->q_ptr)->rm_ops = &xprt_cots_ops;
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate
5327c478bd9Sstevel@tonic-gate out:
533fcfe7086Sgeorges if (error)
5347c478bd9Sstevel@tonic-gate qprocsoff(q);
5357c478bd9Sstevel@tonic-gate
536fcfe7086Sgeorges freemsg(t->info_ack);
537fcfe7086Sgeorges mutex_destroy(&t->lock);
538fcfe7086Sgeorges cv_destroy(&t->wait);
539fcfe7086Sgeorges
5407c478bd9Sstevel@tonic-gate return (error);
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate
5437c478bd9Sstevel@tonic-gate void
rmm_rput(queue_t * q,mblk_t * mp)5447c478bd9Sstevel@tonic-gate rmm_rput(queue_t *q, mblk_t *mp)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_rput)(q, mp);
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate void
rmm_rsrv(queue_t * q)5507c478bd9Sstevel@tonic-gate rmm_rsrv(queue_t *q)
5517c478bd9Sstevel@tonic-gate {
5527c478bd9Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_rsrv)(q);
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate void
rmm_wput(queue_t * q,mblk_t * mp)5567c478bd9Sstevel@tonic-gate rmm_wput(queue_t *q, mblk_t *mp)
5577c478bd9Sstevel@tonic-gate {
5587c478bd9Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_wput)(q, mp);
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate void
rmm_wsrv(queue_t * q)5627c478bd9Sstevel@tonic-gate rmm_wsrv(queue_t *q)
5637c478bd9Sstevel@tonic-gate {
5647c478bd9Sstevel@tonic-gate (*((struct temp_slot *)q->q_ptr)->ops->xo_wsrv)(q);
5657c478bd9Sstevel@tonic-gate }
5667c478bd9Sstevel@tonic-gate
5677c478bd9Sstevel@tonic-gate int
rmm_close(queue_t * q,int flag,cred_t * crp)5687c478bd9Sstevel@tonic-gate rmm_close(queue_t *q, int flag, cred_t *crp)
5697c478bd9Sstevel@tonic-gate {
5707c478bd9Sstevel@tonic-gate return ((*((struct temp_slot *)q->q_ptr)->ops->xo_close)(q, flag, crp));
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate
5732695d4f4SMarcel Telka static void rpcmod_release(queue_t *, mblk_t *, bool_t);
5747c478bd9Sstevel@tonic-gate /*
5757c478bd9Sstevel@tonic-gate * rpcmodopen - open routine gets called when the module gets pushed
5767c478bd9Sstevel@tonic-gate * onto the stream.
5777c478bd9Sstevel@tonic-gate */
5787c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5797c478bd9Sstevel@tonic-gate int
rpcmodopen(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * crp)5807c478bd9Sstevel@tonic-gate rpcmodopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
5817c478bd9Sstevel@tonic-gate {
5827c478bd9Sstevel@tonic-gate struct rpcm *rmp;
5837c478bd9Sstevel@tonic-gate
5842695d4f4SMarcel Telka extern void (*rpc_rele)(queue_t *, mblk_t *, bool_t);
5857c478bd9Sstevel@tonic-gate
5867c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_KRPC, TR_RPCMODOPEN_START, "rpcmodopen_start:");
5877c478bd9Sstevel@tonic-gate
5887c478bd9Sstevel@tonic-gate /*
5897c478bd9Sstevel@tonic-gate * Initialize entry points to release a rpcmod slot (and an input
5907c478bd9Sstevel@tonic-gate * message if supplied) and to send an output message to the module
5917c478bd9Sstevel@tonic-gate * below rpcmod.
5927c478bd9Sstevel@tonic-gate */
5937c478bd9Sstevel@tonic-gate if (rpc_rele == NULL)
5947c478bd9Sstevel@tonic-gate rpc_rele = rpcmod_release;
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate /*
5977c478bd9Sstevel@tonic-gate * Only sufficiently privileged users can use this module, and it
5987c478bd9Sstevel@tonic-gate * is assumed that they will use this module properly, and NOT send
5997c478bd9Sstevel@tonic-gate * bulk data from downstream.
6007c478bd9Sstevel@tonic-gate */
6017c478bd9Sstevel@tonic-gate if (secpolicy_rpcmod_open(crp) != 0)
6027c478bd9Sstevel@tonic-gate return (EPERM);
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate /*
6057c478bd9Sstevel@tonic-gate * Allocate slot data structure.
6067c478bd9Sstevel@tonic-gate */
6077c478bd9Sstevel@tonic-gate rmp = kmem_zalloc(sizeof (*rmp), KM_SLEEP);
6087c478bd9Sstevel@tonic-gate
6097c478bd9Sstevel@tonic-gate mutex_init(&rmp->rm_lock, NULL, MUTEX_DEFAULT, NULL);
6107c478bd9Sstevel@tonic-gate cv_init(&rmp->rm_cwait, NULL, CV_DEFAULT, NULL);
611108322fbScarlsonj rmp->rm_zoneid = rpc_zoneid();
6127c478bd9Sstevel@tonic-gate /*
6137c478bd9Sstevel@tonic-gate * slot type will be set by kRPC client and server ioctl's
6147c478bd9Sstevel@tonic-gate */
6157c478bd9Sstevel@tonic-gate rmp->rm_type = 0;
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate q->q_ptr = (void *)rmp;
6187c478bd9Sstevel@tonic-gate WR(q)->q_ptr = (void *)rmp;
6197c478bd9Sstevel@tonic-gate
6207c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_KRPC, TR_RPCMODOPEN_END, "rpcmodopen_end:(%s)", "end");
6217c478bd9Sstevel@tonic-gate return (0);
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate
6247c478bd9Sstevel@tonic-gate /*
6257c478bd9Sstevel@tonic-gate * rpcmodclose - This routine gets called when the module gets popped
6267c478bd9Sstevel@tonic-gate * off of the stream.
6277c478bd9Sstevel@tonic-gate */
6287c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6297c478bd9Sstevel@tonic-gate int
rpcmodclose(queue_t * q,int flag,cred_t * crp)6307c478bd9Sstevel@tonic-gate rpcmodclose(queue_t *q, int flag, cred_t *crp)
6317c478bd9Sstevel@tonic-gate {
6327c478bd9Sstevel@tonic-gate struct rpcm *rmp;
6337c478bd9Sstevel@tonic-gate
6347c478bd9Sstevel@tonic-gate ASSERT(q != NULL);
6357c478bd9Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr;
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate /*
6387c478bd9Sstevel@tonic-gate * Mark our state as closing.
6397c478bd9Sstevel@tonic-gate */
6407c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock);
6417c478bd9Sstevel@tonic-gate rmp->rm_state |= RM_CLOSING;
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate /*
6447c478bd9Sstevel@tonic-gate * Check and see if there are any messages on the queue. If so, send
6457c478bd9Sstevel@tonic-gate * the messages, regardless whether the downstream module is ready to
6467c478bd9Sstevel@tonic-gate * accept data.
6477c478bd9Sstevel@tonic-gate */
6487c478bd9Sstevel@tonic-gate if (rmp->rm_type == RPC_SERVER) {
6497c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA);
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate qenable(WR(q));
6527c478bd9Sstevel@tonic-gate
6537c478bd9Sstevel@tonic-gate if (rmp->rm_ref) {
6547c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
6557c478bd9Sstevel@tonic-gate /*
6567c478bd9Sstevel@tonic-gate * call into SVC to clean the queue
6577c478bd9Sstevel@tonic-gate */
6587c478bd9Sstevel@tonic-gate svc_queueclean(q);
6597c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock);
6607c478bd9Sstevel@tonic-gate
6617c478bd9Sstevel@tonic-gate /*
6627c478bd9Sstevel@tonic-gate * Block while there are kRPC threads with a reference
6637c478bd9Sstevel@tonic-gate * to this message.
6647c478bd9Sstevel@tonic-gate */
6657c478bd9Sstevel@tonic-gate while (rmp->rm_ref)
6667c478bd9Sstevel@tonic-gate cv_wait(&rmp->rm_cwait, &rmp->rm_lock);
6677c478bd9Sstevel@tonic-gate }
6687c478bd9Sstevel@tonic-gate
6697c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate /*
6727c478bd9Sstevel@tonic-gate * It is now safe to remove this queue from the stream. No kRPC
6737c478bd9Sstevel@tonic-gate * threads have a reference to the stream, and none ever will,
6747c478bd9Sstevel@tonic-gate * because RM_CLOSING is set.
6757c478bd9Sstevel@tonic-gate */
6767c478bd9Sstevel@tonic-gate qprocsoff(q);
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate /* Notify kRPC that this stream is going away. */
6797c478bd9Sstevel@tonic-gate svc_queueclose(q);
6807c478bd9Sstevel@tonic-gate } else {
6817c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
6827c478bd9Sstevel@tonic-gate qprocsoff(q);
6837c478bd9Sstevel@tonic-gate }
6847c478bd9Sstevel@tonic-gate
6857c478bd9Sstevel@tonic-gate q->q_ptr = NULL;
6867c478bd9Sstevel@tonic-gate WR(q)->q_ptr = NULL;
6877c478bd9Sstevel@tonic-gate mutex_destroy(&rmp->rm_lock);
6887c478bd9Sstevel@tonic-gate cv_destroy(&rmp->rm_cwait);
6897c478bd9Sstevel@tonic-gate kmem_free(rmp, sizeof (*rmp));
6907c478bd9Sstevel@tonic-gate return (0);
6917c478bd9Sstevel@tonic-gate }
6927c478bd9Sstevel@tonic-gate
6937c478bd9Sstevel@tonic-gate /*
6947c478bd9Sstevel@tonic-gate * rpcmodrput - Module read put procedure. This is called from
6957c478bd9Sstevel@tonic-gate * the module, driver, or stream head downstream.
6967c478bd9Sstevel@tonic-gate */
6977c478bd9Sstevel@tonic-gate void
rpcmodrput(queue_t * q,mblk_t * mp)6987c478bd9Sstevel@tonic-gate rpcmodrput(queue_t *q, mblk_t *mp)
6997c478bd9Sstevel@tonic-gate {
7007c478bd9Sstevel@tonic-gate struct rpcm *rmp;
7017c478bd9Sstevel@tonic-gate union T_primitives *pptr;
7027c478bd9Sstevel@tonic-gate int hdrsz;
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_KRPC, TR_RPCMODRPUT_START, "rpcmodrput_start:");
7057c478bd9Sstevel@tonic-gate
7067c478bd9Sstevel@tonic-gate ASSERT(q != NULL);
7077c478bd9Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr;
7087c478bd9Sstevel@tonic-gate
7097c478bd9Sstevel@tonic-gate if (rmp->rm_type == 0) {
7107c478bd9Sstevel@tonic-gate freemsg(mp);
7117c478bd9Sstevel@tonic-gate return;
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
7157c478bd9Sstevel@tonic-gate default:
7167c478bd9Sstevel@tonic-gate putnext(q, mp);
7177c478bd9Sstevel@tonic-gate break;
7187c478bd9Sstevel@tonic-gate
7197c478bd9Sstevel@tonic-gate case M_PROTO:
7207c478bd9Sstevel@tonic-gate case M_PCPROTO:
7217c478bd9Sstevel@tonic-gate ASSERT((mp->b_wptr - mp->b_rptr) >= sizeof (int32_t));
7227c478bd9Sstevel@tonic-gate pptr = (union T_primitives *)mp->b_rptr;
7237c478bd9Sstevel@tonic-gate
7247c478bd9Sstevel@tonic-gate /*
7252695d4f4SMarcel Telka * Forward this message to kRPC if it is data.
7267c478bd9Sstevel@tonic-gate */
7277c478bd9Sstevel@tonic-gate if (pptr->type == T_UNITDATA_IND) {
7287c478bd9Sstevel@tonic-gate /*
7297c478bd9Sstevel@tonic-gate * Check if the module is being popped.
7307c478bd9Sstevel@tonic-gate */
7317c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock);
7327c478bd9Sstevel@tonic-gate if (rmp->rm_state & RM_CLOSING) {
7337c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
7347c478bd9Sstevel@tonic-gate putnext(q, mp);
7357c478bd9Sstevel@tonic-gate break;
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate
7387c478bd9Sstevel@tonic-gate switch (rmp->rm_type) {
7397c478bd9Sstevel@tonic-gate case RPC_CLIENT:
7407c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
7417c478bd9Sstevel@tonic-gate hdrsz = mp->b_wptr - mp->b_rptr;
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate /*
7447c478bd9Sstevel@tonic-gate * Make sure the header is sane.
7457c478bd9Sstevel@tonic-gate */
7467c478bd9Sstevel@tonic-gate if (hdrsz < TUNITDATAINDSZ ||
7477c478bd9Sstevel@tonic-gate hdrsz < (pptr->unitdata_ind.OPT_length +
7487c478bd9Sstevel@tonic-gate pptr->unitdata_ind.OPT_offset) ||
7497c478bd9Sstevel@tonic-gate hdrsz < (pptr->unitdata_ind.SRC_length +
7507c478bd9Sstevel@tonic-gate pptr->unitdata_ind.SRC_offset)) {
7517c478bd9Sstevel@tonic-gate freemsg(mp);
7527c478bd9Sstevel@tonic-gate return;
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate /*
75607e75131Sgt29601 * Call clnt_clts_dispatch_notify, so that it
75707e75131Sgt29601 * can pass the message to the proper caller.
75807e75131Sgt29601 * Don't discard the header just yet since the
75907e75131Sgt29601 * client may need the sender's address.
7607c478bd9Sstevel@tonic-gate */
76107e75131Sgt29601 clnt_clts_dispatch_notify(mp, hdrsz,
76207e75131Sgt29601 rmp->rm_zoneid);
7637c478bd9Sstevel@tonic-gate return;
7647c478bd9Sstevel@tonic-gate case RPC_SERVER:
7657c478bd9Sstevel@tonic-gate /*
7667c478bd9Sstevel@tonic-gate * rm_krpc_cell is exclusively used by the kRPC
7672695d4f4SMarcel Telka * CLTS server. Try to submit the message to
7682695d4f4SMarcel Telka * kRPC. Since this is an unreliable channel, we
7692695d4f4SMarcel Telka * can just free the message in case the kRPC
7702695d4f4SMarcel Telka * does not accept new messages.
7717c478bd9Sstevel@tonic-gate */
7722695d4f4SMarcel Telka if (rmp->rm_krpc_cell &&
7732695d4f4SMarcel Telka svc_queuereq(q, mp, TRUE)) {
7747c478bd9Sstevel@tonic-gate /*
7757c478bd9Sstevel@tonic-gate * Raise the reference count on this
7767c478bd9Sstevel@tonic-gate * module to prevent it from being
7772695d4f4SMarcel Telka * popped before kRPC generates the
7787c478bd9Sstevel@tonic-gate * reply.
7797c478bd9Sstevel@tonic-gate */
7807c478bd9Sstevel@tonic-gate rmp->rm_ref++;
7817c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
7827c478bd9Sstevel@tonic-gate } else {
7837c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
7847c478bd9Sstevel@tonic-gate freemsg(mp);
7857c478bd9Sstevel@tonic-gate }
7867c478bd9Sstevel@tonic-gate return;
7877c478bd9Sstevel@tonic-gate default:
7887c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
7897c478bd9Sstevel@tonic-gate freemsg(mp);
7907c478bd9Sstevel@tonic-gate return;
7917c478bd9Sstevel@tonic-gate } /* end switch(rmp->rm_type) */
7927c478bd9Sstevel@tonic-gate } else if (pptr->type == T_UDERROR_IND) {
7937c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock);
7947c478bd9Sstevel@tonic-gate hdrsz = mp->b_wptr - mp->b_rptr;
7957c478bd9Sstevel@tonic-gate
7967c478bd9Sstevel@tonic-gate /*
7977c478bd9Sstevel@tonic-gate * Make sure the header is sane
7987c478bd9Sstevel@tonic-gate */
7997c478bd9Sstevel@tonic-gate if (hdrsz < TUDERRORINDSZ ||
8007c478bd9Sstevel@tonic-gate hdrsz < (pptr->uderror_ind.OPT_length +
8017c478bd9Sstevel@tonic-gate pptr->uderror_ind.OPT_offset) ||
8027c478bd9Sstevel@tonic-gate hdrsz < (pptr->uderror_ind.DEST_length +
8037c478bd9Sstevel@tonic-gate pptr->uderror_ind.DEST_offset)) {
8047c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
8057c478bd9Sstevel@tonic-gate freemsg(mp);
8067c478bd9Sstevel@tonic-gate return;
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate /*
8107c478bd9Sstevel@tonic-gate * In the case where a unit data error has been
8117c478bd9Sstevel@tonic-gate * received, all we need to do is clear the message from
8127c478bd9Sstevel@tonic-gate * the queue.
8137c478bd9Sstevel@tonic-gate */
8147c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
8157c478bd9Sstevel@tonic-gate freemsg(mp);
8167c478bd9Sstevel@tonic-gate RPCLOG(32, "rpcmodrput: unitdata error received at "
8177c478bd9Sstevel@tonic-gate "%ld\n", gethrestime_sec());
8187c478bd9Sstevel@tonic-gate return;
8197c478bd9Sstevel@tonic-gate } /* end else if (pptr->type == T_UDERROR_IND) */
8207c478bd9Sstevel@tonic-gate
8217c478bd9Sstevel@tonic-gate putnext(q, mp);
8227c478bd9Sstevel@tonic-gate break;
8237c478bd9Sstevel@tonic-gate } /* end switch (mp->b_datap->db_type) */
8247c478bd9Sstevel@tonic-gate
8257c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_KRPC, TR_RPCMODRPUT_END,
8267c478bd9Sstevel@tonic-gate "rpcmodrput_end:");
8277c478bd9Sstevel@tonic-gate /*
8287c478bd9Sstevel@tonic-gate * Return codes are not looked at by the STREAMS framework.
8297c478bd9Sstevel@tonic-gate */
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate
8327c478bd9Sstevel@tonic-gate /*
8337c478bd9Sstevel@tonic-gate * write put procedure
8347c478bd9Sstevel@tonic-gate */
8357c478bd9Sstevel@tonic-gate void
rpcmodwput(queue_t * q,mblk_t * mp)8367c478bd9Sstevel@tonic-gate rpcmodwput(queue_t *q, mblk_t *mp)
8377c478bd9Sstevel@tonic-gate {
8387c478bd9Sstevel@tonic-gate struct rpcm *rmp;
8397c478bd9Sstevel@tonic-gate
8407c478bd9Sstevel@tonic-gate ASSERT(q != NULL);
8417c478bd9Sstevel@tonic-gate
8427c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
8437c478bd9Sstevel@tonic-gate case M_PROTO:
8447c478bd9Sstevel@tonic-gate case M_PCPROTO:
8457c478bd9Sstevel@tonic-gate break;
8467c478bd9Sstevel@tonic-gate default:
8477c478bd9Sstevel@tonic-gate rpcmodwput_other(q, mp);
8487c478bd9Sstevel@tonic-gate return;
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate /*
8527c478bd9Sstevel@tonic-gate * Check to see if we can send the message downstream.
8537c478bd9Sstevel@tonic-gate */
8547c478bd9Sstevel@tonic-gate if (canputnext(q)) {
8557c478bd9Sstevel@tonic-gate putnext(q, mp);
8567c478bd9Sstevel@tonic-gate return;
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr;
8607c478bd9Sstevel@tonic-gate ASSERT(rmp != NULL);
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate /*
8637c478bd9Sstevel@tonic-gate * The first canputnext failed. Try again except this time with the
8647c478bd9Sstevel@tonic-gate * lock held, so that we can check the state of the stream to see if
8657c478bd9Sstevel@tonic-gate * it is closing. If either of these conditions evaluate to true
8667c478bd9Sstevel@tonic-gate * then send the meesage.
8677c478bd9Sstevel@tonic-gate */
8687c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock);
8697c478bd9Sstevel@tonic-gate if (canputnext(q) || (rmp->rm_state & RM_CLOSING)) {
8707c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
8717c478bd9Sstevel@tonic-gate putnext(q, mp);
8727c478bd9Sstevel@tonic-gate } else {
8737c478bd9Sstevel@tonic-gate /*
8747c478bd9Sstevel@tonic-gate * canputnext failed again and the stream is not closing.
8757c478bd9Sstevel@tonic-gate * Place the message on the queue and let the service
8767c478bd9Sstevel@tonic-gate * procedure handle the message.
8777c478bd9Sstevel@tonic-gate */
8787c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
8797c478bd9Sstevel@tonic-gate (void) putq(q, mp);
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate
8837c478bd9Sstevel@tonic-gate static void
rpcmodwput_other(queue_t * q,mblk_t * mp)8847c478bd9Sstevel@tonic-gate rpcmodwput_other(queue_t *q, mblk_t *mp)
8857c478bd9Sstevel@tonic-gate {
8867c478bd9Sstevel@tonic-gate struct rpcm *rmp;
8877c478bd9Sstevel@tonic-gate struct iocblk *iocp;
8887c478bd9Sstevel@tonic-gate
8897c478bd9Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr;
8907c478bd9Sstevel@tonic-gate ASSERT(rmp != NULL);
8917c478bd9Sstevel@tonic-gate
8927c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
8937c478bd9Sstevel@tonic-gate case M_IOCTL:
8947c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
8957c478bd9Sstevel@tonic-gate ASSERT(iocp != NULL);
8967c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
8977c478bd9Sstevel@tonic-gate case RPC_CLIENT:
8987c478bd9Sstevel@tonic-gate case RPC_SERVER:
8997c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock);
9007c478bd9Sstevel@tonic-gate rmp->rm_type = iocp->ioc_cmd;
9017c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
9027c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK;
9037c478bd9Sstevel@tonic-gate qreply(q, mp);
9047c478bd9Sstevel@tonic-gate return;
9057c478bd9Sstevel@tonic-gate default:
9067c478bd9Sstevel@tonic-gate /*
9077c478bd9Sstevel@tonic-gate * pass the ioctl downstream and hope someone
9087c478bd9Sstevel@tonic-gate * down there knows how to handle it.
9097c478bd9Sstevel@tonic-gate */
9107c478bd9Sstevel@tonic-gate putnext(q, mp);
9117c478bd9Sstevel@tonic-gate return;
9127c478bd9Sstevel@tonic-gate }
9137c478bd9Sstevel@tonic-gate default:
9147c478bd9Sstevel@tonic-gate break;
9157c478bd9Sstevel@tonic-gate }
9167c478bd9Sstevel@tonic-gate /*
9177c478bd9Sstevel@tonic-gate * This is something we definitely do not know how to handle, just
9187c478bd9Sstevel@tonic-gate * pass the message downstream
9197c478bd9Sstevel@tonic-gate */
9207c478bd9Sstevel@tonic-gate putnext(q, mp);
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate
9237c478bd9Sstevel@tonic-gate /*
9247c478bd9Sstevel@tonic-gate * Module write service procedure. This is called by downstream modules
9257c478bd9Sstevel@tonic-gate * for back enabling during flow control.
9267c478bd9Sstevel@tonic-gate */
9277c478bd9Sstevel@tonic-gate void
rpcmodwsrv(queue_t * q)9287c478bd9Sstevel@tonic-gate rpcmodwsrv(queue_t *q)
9297c478bd9Sstevel@tonic-gate {
9307c478bd9Sstevel@tonic-gate struct rpcm *rmp;
9317c478bd9Sstevel@tonic-gate mblk_t *mp = NULL;
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr;
9347c478bd9Sstevel@tonic-gate ASSERT(rmp != NULL);
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate /*
9377c478bd9Sstevel@tonic-gate * Get messages that may be queued and send them down stream
9387c478bd9Sstevel@tonic-gate */
9397c478bd9Sstevel@tonic-gate while ((mp = getq(q)) != NULL) {
9407c478bd9Sstevel@tonic-gate /*
9417c478bd9Sstevel@tonic-gate * Optimize the service procedure for the server-side, by
9427c478bd9Sstevel@tonic-gate * avoiding a call to canputnext().
9437c478bd9Sstevel@tonic-gate */
9447c478bd9Sstevel@tonic-gate if (rmp->rm_type == RPC_SERVER || canputnext(q)) {
9457c478bd9Sstevel@tonic-gate putnext(q, mp);
9467c478bd9Sstevel@tonic-gate continue;
9477c478bd9Sstevel@tonic-gate }
9487c478bd9Sstevel@tonic-gate (void) putbq(q, mp);
9497c478bd9Sstevel@tonic-gate return;
9507c478bd9Sstevel@tonic-gate }
9517c478bd9Sstevel@tonic-gate }
9527c478bd9Sstevel@tonic-gate
9532695d4f4SMarcel Telka /* ARGSUSED */
9547c478bd9Sstevel@tonic-gate static void
rpcmod_release(queue_t * q,mblk_t * bp,bool_t enable)9552695d4f4SMarcel Telka rpcmod_release(queue_t *q, mblk_t *bp, bool_t enable)
9567c478bd9Sstevel@tonic-gate {
9577c478bd9Sstevel@tonic-gate struct rpcm *rmp;
9587c478bd9Sstevel@tonic-gate
9597c478bd9Sstevel@tonic-gate /*
9607c478bd9Sstevel@tonic-gate * For now, just free the message.
9617c478bd9Sstevel@tonic-gate */
9627c478bd9Sstevel@tonic-gate if (bp)
9637c478bd9Sstevel@tonic-gate freemsg(bp);
9647c478bd9Sstevel@tonic-gate rmp = (struct rpcm *)q->q_ptr;
9657c478bd9Sstevel@tonic-gate
9667c478bd9Sstevel@tonic-gate mutex_enter(&rmp->rm_lock);
9677c478bd9Sstevel@tonic-gate rmp->rm_ref--;
9687c478bd9Sstevel@tonic-gate
9697c478bd9Sstevel@tonic-gate if (rmp->rm_ref == 0 && (rmp->rm_state & RM_CLOSING)) {
9707c478bd9Sstevel@tonic-gate cv_broadcast(&rmp->rm_cwait);
9717c478bd9Sstevel@tonic-gate }
9727c478bd9Sstevel@tonic-gate
9737c478bd9Sstevel@tonic-gate mutex_exit(&rmp->rm_lock);
9747c478bd9Sstevel@tonic-gate }
9757c478bd9Sstevel@tonic-gate
9767c478bd9Sstevel@tonic-gate /*
9777c478bd9Sstevel@tonic-gate * This part of rpcmod is pushed on a connection-oriented transport for use
9787c478bd9Sstevel@tonic-gate * by RPC. It serves to bypass the Stream head, implements
9797c478bd9Sstevel@tonic-gate * the record marking protocol, and dispatches incoming RPC messages.
9807c478bd9Sstevel@tonic-gate */
9817c478bd9Sstevel@tonic-gate
9827c478bd9Sstevel@tonic-gate /* Default idle timer values */
9837c478bd9Sstevel@tonic-gate #define MIR_CLNT_IDLE_TIMEOUT (5 * (60 * 1000L)) /* 5 minutes */
9847c478bd9Sstevel@tonic-gate #define MIR_SVC_IDLE_TIMEOUT (6 * (60 * 1000L)) /* 6 minutes */
9857c478bd9Sstevel@tonic-gate #define MIR_SVC_ORDREL_TIMEOUT (10 * (60 * 1000L)) /* 10 minutes */
9867c478bd9Sstevel@tonic-gate #define MIR_LASTFRAG 0x80000000 /* Record marker */
9877c478bd9Sstevel@tonic-gate
9887c478bd9Sstevel@tonic-gate #define MIR_SVC_QUIESCED(mir) \
9897c478bd9Sstevel@tonic-gate (mir->mir_ref_cnt == 0 && mir->mir_inrservice == 0)
9907c478bd9Sstevel@tonic-gate
9917c478bd9Sstevel@tonic-gate #define MIR_CLEAR_INRSRV(mir_ptr) { \
9927c478bd9Sstevel@tonic-gate (mir_ptr)->mir_inrservice = 0; \
9937c478bd9Sstevel@tonic-gate if ((mir_ptr)->mir_type == RPC_SERVER && \
9947c478bd9Sstevel@tonic-gate (mir_ptr)->mir_closing) \
9957c478bd9Sstevel@tonic-gate cv_signal(&(mir_ptr)->mir_condvar); \
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate
9987c478bd9Sstevel@tonic-gate /*
9997c478bd9Sstevel@tonic-gate * Don't block service procedure (and mir_close) if
10007c478bd9Sstevel@tonic-gate * we are in the process of closing.
10017c478bd9Sstevel@tonic-gate */
10027c478bd9Sstevel@tonic-gate #define MIR_WCANPUTNEXT(mir_ptr, write_q) \
10037c478bd9Sstevel@tonic-gate (canputnext(write_q) || ((mir_ptr)->mir_svc_no_more_msgs == 1))
10047c478bd9Sstevel@tonic-gate
10057c478bd9Sstevel@tonic-gate static int mir_clnt_dup_request(queue_t *q, mblk_t *mp);
10067c478bd9Sstevel@tonic-gate static void mir_rput_proto(queue_t *q, mblk_t *mp);
10077c478bd9Sstevel@tonic-gate static int mir_svc_policy_notify(queue_t *q, int event);
10082695d4f4SMarcel Telka static void mir_svc_release(queue_t *wq, mblk_t *mp, bool_t);
10097c478bd9Sstevel@tonic-gate static void mir_svc_start(queue_t *wq);
10107c478bd9Sstevel@tonic-gate static void mir_svc_idle_start(queue_t *, mir_t *);
10117c478bd9Sstevel@tonic-gate static void mir_svc_idle_stop(queue_t *, mir_t *);
10127c478bd9Sstevel@tonic-gate static void mir_svc_start_close(queue_t *, mir_t *);
10137c478bd9Sstevel@tonic-gate static void mir_clnt_idle_do_stop(queue_t *);
10147c478bd9Sstevel@tonic-gate static void mir_clnt_idle_stop(queue_t *, mir_t *);
10157c478bd9Sstevel@tonic-gate static void mir_clnt_idle_start(queue_t *, mir_t *);
10167c478bd9Sstevel@tonic-gate static void mir_wput(queue_t *q, mblk_t *mp);
10177c478bd9Sstevel@tonic-gate static void mir_wput_other(queue_t *q, mblk_t *mp);
10187c478bd9Sstevel@tonic-gate static void mir_wsrv(queue_t *q);
10197c478bd9Sstevel@tonic-gate static void mir_disconnect(queue_t *, mir_t *ir);
1020*3b3b7026SMarcel Telka static int mir_check_len(queue_t *, mblk_t *);
10217c478bd9Sstevel@tonic-gate static void mir_timer(void *);
10227c478bd9Sstevel@tonic-gate
10232695d4f4SMarcel Telka extern void (*mir_rele)(queue_t *, mblk_t *, bool_t);
10247c478bd9Sstevel@tonic-gate extern void (*mir_start)(queue_t *);
10257c478bd9Sstevel@tonic-gate extern void (*clnt_stop_idle)(queue_t *);
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate clock_t clnt_idle_timeout = MIR_CLNT_IDLE_TIMEOUT;
10287c478bd9Sstevel@tonic-gate clock_t svc_idle_timeout = MIR_SVC_IDLE_TIMEOUT;
10297c478bd9Sstevel@tonic-gate
10307c478bd9Sstevel@tonic-gate /*
10317c478bd9Sstevel@tonic-gate * Timeout for subsequent notifications of idle connection. This is
10327c478bd9Sstevel@tonic-gate * typically used to clean up after a wedged orderly release.
10337c478bd9Sstevel@tonic-gate */
10347c478bd9Sstevel@tonic-gate clock_t svc_ordrel_timeout = MIR_SVC_ORDREL_TIMEOUT; /* milliseconds */
10357c478bd9Sstevel@tonic-gate
10367c478bd9Sstevel@tonic-gate extern uint_t *clnt_max_msg_sizep;
10377c478bd9Sstevel@tonic-gate extern uint_t *svc_max_msg_sizep;
10387c478bd9Sstevel@tonic-gate uint_t clnt_max_msg_size = RPC_MAXDATASIZE;
10397c478bd9Sstevel@tonic-gate uint_t svc_max_msg_size = RPC_MAXDATASIZE;
10407c478bd9Sstevel@tonic-gate uint_t mir_krpc_cell_null;
10417c478bd9Sstevel@tonic-gate
10427c478bd9Sstevel@tonic-gate static void
mir_timer_stop(mir_t * mir)10437c478bd9Sstevel@tonic-gate mir_timer_stop(mir_t *mir)
10447c478bd9Sstevel@tonic-gate {
10457c478bd9Sstevel@tonic-gate timeout_id_t tid;
10467c478bd9Sstevel@tonic-gate
10477c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
10487c478bd9Sstevel@tonic-gate
10497c478bd9Sstevel@tonic-gate /*
10507c478bd9Sstevel@tonic-gate * Since the mir_mutex lock needs to be released to call
10517c478bd9Sstevel@tonic-gate * untimeout(), we need to make sure that no other thread
10527c478bd9Sstevel@tonic-gate * can start/stop the timer (changing mir_timer_id) during
10537c478bd9Sstevel@tonic-gate * that time. The mir_timer_call bit and the mir_timer_cv
10547c478bd9Sstevel@tonic-gate * condition variable are used to synchronize this. Setting
10557c478bd9Sstevel@tonic-gate * mir_timer_call also tells mir_timer() (refer to the comments
10567c478bd9Sstevel@tonic-gate * in mir_timer()) that it does not need to do anything.
10577c478bd9Sstevel@tonic-gate */
10587c478bd9Sstevel@tonic-gate while (mir->mir_timer_call)
10597c478bd9Sstevel@tonic-gate cv_wait(&mir->mir_timer_cv, &mir->mir_mutex);
10607c478bd9Sstevel@tonic-gate mir->mir_timer_call = B_TRUE;
10617c478bd9Sstevel@tonic-gate
10627c478bd9Sstevel@tonic-gate if ((tid = mir->mir_timer_id) != 0) {
10637c478bd9Sstevel@tonic-gate mir->mir_timer_id = 0;
10647c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
10657c478bd9Sstevel@tonic-gate (void) untimeout(tid);
10667c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
10677c478bd9Sstevel@tonic-gate }
10687c478bd9Sstevel@tonic-gate mir->mir_timer_call = B_FALSE;
10697c478bd9Sstevel@tonic-gate cv_broadcast(&mir->mir_timer_cv);
10707c478bd9Sstevel@tonic-gate }
10717c478bd9Sstevel@tonic-gate
10727c478bd9Sstevel@tonic-gate static void
mir_timer_start(queue_t * q,mir_t * mir,clock_t intrvl)10737c478bd9Sstevel@tonic-gate mir_timer_start(queue_t *q, mir_t *mir, clock_t intrvl)
10747c478bd9Sstevel@tonic-gate {
10757c478bd9Sstevel@tonic-gate timeout_id_t tid;
10767c478bd9Sstevel@tonic-gate
10777c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
10787c478bd9Sstevel@tonic-gate
10797c478bd9Sstevel@tonic-gate while (mir->mir_timer_call)
10807c478bd9Sstevel@tonic-gate cv_wait(&mir->mir_timer_cv, &mir->mir_mutex);
10817c478bd9Sstevel@tonic-gate mir->mir_timer_call = B_TRUE;
10827c478bd9Sstevel@tonic-gate
10837c478bd9Sstevel@tonic-gate if ((tid = mir->mir_timer_id) != 0) {
10847c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
10857c478bd9Sstevel@tonic-gate (void) untimeout(tid);
10867c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
10877c478bd9Sstevel@tonic-gate }
10887c478bd9Sstevel@tonic-gate /* Only start the timer when it is not closing. */
10897c478bd9Sstevel@tonic-gate if (!mir->mir_closing) {
10907c478bd9Sstevel@tonic-gate mir->mir_timer_id = timeout(mir_timer, q,
10917c478bd9Sstevel@tonic-gate MSEC_TO_TICK(intrvl));
10927c478bd9Sstevel@tonic-gate }
10937c478bd9Sstevel@tonic-gate mir->mir_timer_call = B_FALSE;
10947c478bd9Sstevel@tonic-gate cv_broadcast(&mir->mir_timer_cv);
10957c478bd9Sstevel@tonic-gate }
10967c478bd9Sstevel@tonic-gate
10977c478bd9Sstevel@tonic-gate static int
mir_clnt_dup_request(queue_t * q,mblk_t * mp)10987c478bd9Sstevel@tonic-gate mir_clnt_dup_request(queue_t *q, mblk_t *mp)
10997c478bd9Sstevel@tonic-gate {
11007c478bd9Sstevel@tonic-gate mblk_t *mp1;
11017c478bd9Sstevel@tonic-gate uint32_t new_xid;
11027c478bd9Sstevel@tonic-gate uint32_t old_xid;
11037c478bd9Sstevel@tonic-gate
11047c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&((mir_t *)q->q_ptr)->mir_mutex));
11057c478bd9Sstevel@tonic-gate new_xid = BE32_TO_U32(&mp->b_rptr[4]);
11067c478bd9Sstevel@tonic-gate /*
11077c478bd9Sstevel@tonic-gate * This loop is a bit tacky -- it walks the STREAMS list of
11087c478bd9Sstevel@tonic-gate * flow-controlled messages.
11097c478bd9Sstevel@tonic-gate */
11107c478bd9Sstevel@tonic-gate if ((mp1 = q->q_first) != NULL) {
11117c478bd9Sstevel@tonic-gate do {
11127c478bd9Sstevel@tonic-gate old_xid = BE32_TO_U32(&mp1->b_rptr[4]);
11137c478bd9Sstevel@tonic-gate if (new_xid == old_xid)
11147c478bd9Sstevel@tonic-gate return (1);
11157c478bd9Sstevel@tonic-gate } while ((mp1 = mp1->b_next) != NULL);
11167c478bd9Sstevel@tonic-gate }
11177c478bd9Sstevel@tonic-gate return (0);
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate
11207c478bd9Sstevel@tonic-gate static int
mir_close(queue_t * q)11217c478bd9Sstevel@tonic-gate mir_close(queue_t *q)
11227c478bd9Sstevel@tonic-gate {
112375320802Smeem mir_t *mir = q->q_ptr;
11247c478bd9Sstevel@tonic-gate mblk_t *mp;
11257c478bd9Sstevel@tonic-gate bool_t queue_cleaned = FALSE;
11267c478bd9Sstevel@tonic-gate
11277c478bd9Sstevel@tonic-gate RPCLOG(32, "rpcmod: mir_close of q 0x%p\n", (void *)q);
11287c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
11297c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
11307c478bd9Sstevel@tonic-gate if ((mp = mir->mir_head_mp) != NULL) {
113175320802Smeem mir->mir_head_mp = NULL;
113275320802Smeem mir->mir_tail_mp = NULL;
11337c478bd9Sstevel@tonic-gate freemsg(mp);
11347c478bd9Sstevel@tonic-gate }
11357c478bd9Sstevel@tonic-gate /*
11367c478bd9Sstevel@tonic-gate * Set mir_closing so we get notified when MIR_SVC_QUIESCED()
11377c478bd9Sstevel@tonic-gate * is TRUE. And mir_timer_start() won't start the timer again.
11387c478bd9Sstevel@tonic-gate */
11397c478bd9Sstevel@tonic-gate mir->mir_closing = B_TRUE;
11407c478bd9Sstevel@tonic-gate mir_timer_stop(mir);
11417c478bd9Sstevel@tonic-gate
11427c478bd9Sstevel@tonic-gate if (mir->mir_type == RPC_SERVER) {
11437c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); /* Ditch anything waiting on read q */
11447c478bd9Sstevel@tonic-gate
11457c478bd9Sstevel@tonic-gate /*
11467c478bd9Sstevel@tonic-gate * This will prevent more requests from arriving and
11477c478bd9Sstevel@tonic-gate * will force rpcmod to ignore flow control.
11487c478bd9Sstevel@tonic-gate */
11497c478bd9Sstevel@tonic-gate mir_svc_start_close(WR(q), mir);
11507c478bd9Sstevel@tonic-gate
11517c478bd9Sstevel@tonic-gate while ((!MIR_SVC_QUIESCED(mir)) || mir->mir_inwservice == 1) {
11527c478bd9Sstevel@tonic-gate
11537c478bd9Sstevel@tonic-gate if (mir->mir_ref_cnt && !mir->mir_inrservice &&
11547c478bd9Sstevel@tonic-gate (queue_cleaned == FALSE)) {
11557c478bd9Sstevel@tonic-gate /*
11567c478bd9Sstevel@tonic-gate * call into SVC to clean the queue
11577c478bd9Sstevel@tonic-gate */
11587c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
11597c478bd9Sstevel@tonic-gate svc_queueclean(q);
11607c478bd9Sstevel@tonic-gate queue_cleaned = TRUE;
11617c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
11627c478bd9Sstevel@tonic-gate continue;
11637c478bd9Sstevel@tonic-gate }
11647c478bd9Sstevel@tonic-gate
11657c478bd9Sstevel@tonic-gate /*
11667c478bd9Sstevel@tonic-gate * Bugid 1253810 - Force the write service
11677c478bd9Sstevel@tonic-gate * procedure to send its messages, regardless
11687c478bd9Sstevel@tonic-gate * whether the downstream module is ready
11697c478bd9Sstevel@tonic-gate * to accept data.
11707c478bd9Sstevel@tonic-gate */
11717c478bd9Sstevel@tonic-gate if (mir->mir_inwservice == 1)
11727c478bd9Sstevel@tonic-gate qenable(WR(q));
11737c478bd9Sstevel@tonic-gate
11747c478bd9Sstevel@tonic-gate cv_wait(&mir->mir_condvar, &mir->mir_mutex);
11757c478bd9Sstevel@tonic-gate }
11767c478bd9Sstevel@tonic-gate
11777c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
11787c478bd9Sstevel@tonic-gate qprocsoff(q);
11797c478bd9Sstevel@tonic-gate
11802695d4f4SMarcel Telka /* Notify kRPC that this stream is going away. */
11817c478bd9Sstevel@tonic-gate svc_queueclose(q);
11827c478bd9Sstevel@tonic-gate } else {
11837c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
11847c478bd9Sstevel@tonic-gate qprocsoff(q);
11857c478bd9Sstevel@tonic-gate }
11867c478bd9Sstevel@tonic-gate
11877c478bd9Sstevel@tonic-gate mutex_destroy(&mir->mir_mutex);
11887c478bd9Sstevel@tonic-gate cv_destroy(&mir->mir_condvar);
11897c478bd9Sstevel@tonic-gate cv_destroy(&mir->mir_timer_cv);
11907c478bd9Sstevel@tonic-gate kmem_free(mir, sizeof (mir_t));
11917c478bd9Sstevel@tonic-gate return (0);
11927c478bd9Sstevel@tonic-gate }
11937c478bd9Sstevel@tonic-gate
11947c478bd9Sstevel@tonic-gate /*
11957c478bd9Sstevel@tonic-gate * This is server side only (RPC_SERVER).
11967c478bd9Sstevel@tonic-gate *
11977c478bd9Sstevel@tonic-gate * Exit idle mode.
11987c478bd9Sstevel@tonic-gate */
11997c478bd9Sstevel@tonic-gate static void
mir_svc_idle_stop(queue_t * q,mir_t * mir)12007c478bd9Sstevel@tonic-gate mir_svc_idle_stop(queue_t *q, mir_t *mir)
12017c478bd9Sstevel@tonic-gate {
12027c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
12037c478bd9Sstevel@tonic-gate ASSERT((q->q_flag & QREADR) == 0);
12047c478bd9Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER);
12057c478bd9Sstevel@tonic-gate RPCLOG(16, "rpcmod: mir_svc_idle_stop of q 0x%p\n", (void *)q);
12067c478bd9Sstevel@tonic-gate
12077c478bd9Sstevel@tonic-gate mir_timer_stop(mir);
12087c478bd9Sstevel@tonic-gate }
12097c478bd9Sstevel@tonic-gate
12107c478bd9Sstevel@tonic-gate /*
12117c478bd9Sstevel@tonic-gate * This is server side only (RPC_SERVER).
12127c478bd9Sstevel@tonic-gate *
12137c478bd9Sstevel@tonic-gate * Start idle processing, which will include setting idle timer if the
12147c478bd9Sstevel@tonic-gate * stream is not being closed.
12157c478bd9Sstevel@tonic-gate */
12167c478bd9Sstevel@tonic-gate static void
mir_svc_idle_start(queue_t * q,mir_t * mir)12177c478bd9Sstevel@tonic-gate mir_svc_idle_start(queue_t *q, mir_t *mir)
12187c478bd9Sstevel@tonic-gate {
12197c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
12207c478bd9Sstevel@tonic-gate ASSERT((q->q_flag & QREADR) == 0);
12217c478bd9Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER);
12227c478bd9Sstevel@tonic-gate RPCLOG(16, "rpcmod: mir_svc_idle_start q 0x%p\n", (void *)q);
12237c478bd9Sstevel@tonic-gate
12247c478bd9Sstevel@tonic-gate /*
12257c478bd9Sstevel@tonic-gate * Don't re-start idle timer if we are closing queues.
12267c478bd9Sstevel@tonic-gate */
12277c478bd9Sstevel@tonic-gate if (mir->mir_closing) {
12287c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_svc_idle_start - closing: 0x%p\n",
12297c478bd9Sstevel@tonic-gate (void *)q);
12307c478bd9Sstevel@tonic-gate
12317c478bd9Sstevel@tonic-gate /*
12327c478bd9Sstevel@tonic-gate * We will call mir_svc_idle_start() whenever MIR_SVC_QUIESCED()
12337c478bd9Sstevel@tonic-gate * is true. When it is true, and we are in the process of
12347c478bd9Sstevel@tonic-gate * closing the stream, signal any thread waiting in
12357c478bd9Sstevel@tonic-gate * mir_close().
12367c478bd9Sstevel@tonic-gate */
12377c478bd9Sstevel@tonic-gate if (mir->mir_inwservice == 0)
12387c478bd9Sstevel@tonic-gate cv_signal(&mir->mir_condvar);
12397c478bd9Sstevel@tonic-gate
12407c478bd9Sstevel@tonic-gate } else {
12417c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_svc_idle_start - reset %s timer\n",
12427c478bd9Sstevel@tonic-gate mir->mir_ordrel_pending ? "ordrel" : "normal");
12437c478bd9Sstevel@tonic-gate /*
12447c478bd9Sstevel@tonic-gate * Normal condition, start the idle timer. If an orderly
12457c478bd9Sstevel@tonic-gate * release has been sent, set the timeout to wait for the
12467c478bd9Sstevel@tonic-gate * client to close its side of the connection. Otherwise,
12477c478bd9Sstevel@tonic-gate * use the normal idle timeout.
12487c478bd9Sstevel@tonic-gate */
12497c478bd9Sstevel@tonic-gate mir_timer_start(q, mir, mir->mir_ordrel_pending ?
12507c478bd9Sstevel@tonic-gate svc_ordrel_timeout : mir->mir_idle_timeout);
12517c478bd9Sstevel@tonic-gate }
12527c478bd9Sstevel@tonic-gate }
12537c478bd9Sstevel@tonic-gate
12547c478bd9Sstevel@tonic-gate /* ARGSUSED */
12557c478bd9Sstevel@tonic-gate static int
mir_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)12567c478bd9Sstevel@tonic-gate mir_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
12577c478bd9Sstevel@tonic-gate {
12587c478bd9Sstevel@tonic-gate mir_t *mir;
12597c478bd9Sstevel@tonic-gate
12607c478bd9Sstevel@tonic-gate RPCLOG(32, "rpcmod: mir_open of q 0x%p\n", (void *)q);
12612695d4f4SMarcel Telka /* Set variables used directly by kRPC. */
12627c478bd9Sstevel@tonic-gate if (!mir_rele)
12637c478bd9Sstevel@tonic-gate mir_rele = mir_svc_release;
12647c478bd9Sstevel@tonic-gate if (!mir_start)
12657c478bd9Sstevel@tonic-gate mir_start = mir_svc_start;
12667c478bd9Sstevel@tonic-gate if (!clnt_stop_idle)
12677c478bd9Sstevel@tonic-gate clnt_stop_idle = mir_clnt_idle_do_stop;
12687c478bd9Sstevel@tonic-gate if (!clnt_max_msg_sizep)
12697c478bd9Sstevel@tonic-gate clnt_max_msg_sizep = &clnt_max_msg_size;
12707c478bd9Sstevel@tonic-gate if (!svc_max_msg_sizep)
12717c478bd9Sstevel@tonic-gate svc_max_msg_sizep = &svc_max_msg_size;
12727c478bd9Sstevel@tonic-gate
12737c478bd9Sstevel@tonic-gate /* Allocate a zero'ed out mir structure for this stream. */
12747c478bd9Sstevel@tonic-gate mir = kmem_zalloc(sizeof (mir_t), KM_SLEEP);
12757c478bd9Sstevel@tonic-gate
12767c478bd9Sstevel@tonic-gate /*
12777c478bd9Sstevel@tonic-gate * We set hold inbound here so that incoming messages will
12787c478bd9Sstevel@tonic-gate * be held on the read-side queue until the stream is completely
12797c478bd9Sstevel@tonic-gate * initialized with a RPC_CLIENT or RPC_SERVER ioctl. During
12807c478bd9Sstevel@tonic-gate * the ioctl processing, the flag is cleared and any messages that
12812695d4f4SMarcel Telka * arrived between the open and the ioctl are delivered to kRPC.
12827c478bd9Sstevel@tonic-gate *
12837c478bd9Sstevel@tonic-gate * Early data should never arrive on a client stream since
12847c478bd9Sstevel@tonic-gate * servers only respond to our requests and we do not send any.
12857c478bd9Sstevel@tonic-gate * until after the stream is initialized. Early data is
12867c478bd9Sstevel@tonic-gate * very common on a server stream where the client will start
12877c478bd9Sstevel@tonic-gate * sending data as soon as the connection is made (and this
12887c478bd9Sstevel@tonic-gate * is especially true with TCP where the protocol accepts the
12892695d4f4SMarcel Telka * connection before nfsd or kRPC is notified about it).
12907c478bd9Sstevel@tonic-gate */
12917c478bd9Sstevel@tonic-gate
12927c478bd9Sstevel@tonic-gate mir->mir_hold_inbound = 1;
12937c478bd9Sstevel@tonic-gate
12947c478bd9Sstevel@tonic-gate /*
12957c478bd9Sstevel@tonic-gate * Start the record marker looking for a 4-byte header. When
12967c478bd9Sstevel@tonic-gate * this length is negative, it indicates that rpcmod is looking
12977c478bd9Sstevel@tonic-gate * for bytes to consume for the record marker header. When it
12987c478bd9Sstevel@tonic-gate * is positive, it holds the number of bytes that have arrived
12997c478bd9Sstevel@tonic-gate * for the current fragment and are being held in mir_header_mp.
13007c478bd9Sstevel@tonic-gate */
13017c478bd9Sstevel@tonic-gate
13027c478bd9Sstevel@tonic-gate mir->mir_frag_len = -(int32_t)sizeof (uint32_t);
13037c478bd9Sstevel@tonic-gate
1304108322fbScarlsonj mir->mir_zoneid = rpc_zoneid();
13057c478bd9Sstevel@tonic-gate mutex_init(&mir->mir_mutex, NULL, MUTEX_DEFAULT, NULL);
13067c478bd9Sstevel@tonic-gate cv_init(&mir->mir_condvar, NULL, CV_DRIVER, NULL);
13077c478bd9Sstevel@tonic-gate cv_init(&mir->mir_timer_cv, NULL, CV_DRIVER, NULL);
13087c478bd9Sstevel@tonic-gate
13097c478bd9Sstevel@tonic-gate q->q_ptr = (char *)mir;
13107c478bd9Sstevel@tonic-gate WR(q)->q_ptr = (char *)mir;
13117c478bd9Sstevel@tonic-gate
13127c478bd9Sstevel@tonic-gate /*
13137c478bd9Sstevel@tonic-gate * We noenable the read-side queue because we don't want it
13147c478bd9Sstevel@tonic-gate * automatically enabled by putq. We enable it explicitly
13157c478bd9Sstevel@tonic-gate * in mir_wsrv when appropriate. (See additional comments on
13167c478bd9Sstevel@tonic-gate * flow control at the beginning of mir_rsrv.)
13177c478bd9Sstevel@tonic-gate */
13187c478bd9Sstevel@tonic-gate noenable(q);
13197c478bd9Sstevel@tonic-gate
13207c478bd9Sstevel@tonic-gate qprocson(q);
13217c478bd9Sstevel@tonic-gate return (0);
13227c478bd9Sstevel@tonic-gate }
13237c478bd9Sstevel@tonic-gate
13247c478bd9Sstevel@tonic-gate /*
13257c478bd9Sstevel@tonic-gate * Read-side put routine for both the client and server side. Does the
13267c478bd9Sstevel@tonic-gate * record marking for incoming RPC messages, and when complete, dispatches
13277c478bd9Sstevel@tonic-gate * the message to either the client or server.
13287c478bd9Sstevel@tonic-gate */
13297c478bd9Sstevel@tonic-gate static void
mir_rput(queue_t * q,mblk_t * mp)1330153adbb6Smeem mir_rput(queue_t *q, mblk_t *mp)
13317c478bd9Sstevel@tonic-gate {
13327c478bd9Sstevel@tonic-gate int excess;
1333153adbb6Smeem int32_t frag_len, frag_header;
1334153adbb6Smeem mblk_t *cont_mp, *head_mp, *tail_mp, *mp1;
1335153adbb6Smeem mir_t *mir = q->q_ptr;
13367c478bd9Sstevel@tonic-gate boolean_t stop_timer = B_FALSE;
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate ASSERT(mir != NULL);
13397c478bd9Sstevel@tonic-gate
13407c478bd9Sstevel@tonic-gate /*
13417c478bd9Sstevel@tonic-gate * If the stream has not been set up as a RPC_CLIENT or RPC_SERVER
13427c478bd9Sstevel@tonic-gate * with the corresponding ioctl, then don't accept
13437c478bd9Sstevel@tonic-gate * any inbound data. This should never happen for streams
13442695d4f4SMarcel Telka * created by nfsd or client-side kRPC because they are careful
13457c478bd9Sstevel@tonic-gate * to set the mode of the stream before doing anything else.
13467c478bd9Sstevel@tonic-gate */
13477c478bd9Sstevel@tonic-gate if (mir->mir_type == 0) {
13487c478bd9Sstevel@tonic-gate freemsg(mp);
13497c478bd9Sstevel@tonic-gate return;
13507c478bd9Sstevel@tonic-gate }
13517c478bd9Sstevel@tonic-gate
13527c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
13537c478bd9Sstevel@tonic-gate
13547c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
13557c478bd9Sstevel@tonic-gate case M_DATA:
13567c478bd9Sstevel@tonic-gate break;
13577c478bd9Sstevel@tonic-gate case M_PROTO:
13587c478bd9Sstevel@tonic-gate case M_PCPROTO:
1359153adbb6Smeem if (MBLKL(mp) < sizeof (t_scalar_t)) {
13607c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_rput: runt TPI message (%d bytes)\n",
1361153adbb6Smeem (int)MBLKL(mp));
13627c478bd9Sstevel@tonic-gate freemsg(mp);
13637c478bd9Sstevel@tonic-gate return;
13647c478bd9Sstevel@tonic-gate }
1365153adbb6Smeem if (((union T_primitives *)mp->b_rptr)->type != T_DATA_IND) {
13667c478bd9Sstevel@tonic-gate mir_rput_proto(q, mp);
13677c478bd9Sstevel@tonic-gate return;
13687c478bd9Sstevel@tonic-gate }
13697c478bd9Sstevel@tonic-gate
13707c478bd9Sstevel@tonic-gate /* Throw away the T_DATA_IND block and continue with data. */
13717c478bd9Sstevel@tonic-gate mp1 = mp;
13727c478bd9Sstevel@tonic-gate mp = mp->b_cont;
13737c478bd9Sstevel@tonic-gate freeb(mp1);
13747c478bd9Sstevel@tonic-gate break;
13757c478bd9Sstevel@tonic-gate case M_SETOPTS:
13767c478bd9Sstevel@tonic-gate /*
13777c478bd9Sstevel@tonic-gate * If a module on the stream is trying set the Stream head's
13787c478bd9Sstevel@tonic-gate * high water mark, then set our hiwater to the requested
13797c478bd9Sstevel@tonic-gate * value. We are the "stream head" for all inbound
13802695d4f4SMarcel Telka * data messages since messages are passed directly to kRPC.
13817c478bd9Sstevel@tonic-gate */
1382153adbb6Smeem if (MBLKL(mp) >= sizeof (struct stroptions)) {
13837c478bd9Sstevel@tonic-gate struct stroptions *stropts;
13847c478bd9Sstevel@tonic-gate
13857c478bd9Sstevel@tonic-gate stropts = (struct stroptions *)mp->b_rptr;
13867c478bd9Sstevel@tonic-gate if ((stropts->so_flags & SO_HIWAT) &&
13877c478bd9Sstevel@tonic-gate !(stropts->so_flags & SO_BAND)) {
13887c478bd9Sstevel@tonic-gate (void) strqset(q, QHIWAT, 0, stropts->so_hiwat);
13897c478bd9Sstevel@tonic-gate }
13907c478bd9Sstevel@tonic-gate }
13917c478bd9Sstevel@tonic-gate putnext(q, mp);
13927c478bd9Sstevel@tonic-gate return;
13937c478bd9Sstevel@tonic-gate case M_FLUSH:
1394153adbb6Smeem RPCLOG(32, "mir_rput: ignoring M_FLUSH %x ", *mp->b_rptr);
1395153adbb6Smeem RPCLOG(32, "on q 0x%p\n", (void *)q);
13967c478bd9Sstevel@tonic-gate putnext(q, mp);
13977c478bd9Sstevel@tonic-gate return;
13987c478bd9Sstevel@tonic-gate default:
13997c478bd9Sstevel@tonic-gate putnext(q, mp);
14007c478bd9Sstevel@tonic-gate return;
14017c478bd9Sstevel@tonic-gate }
14027c478bd9Sstevel@tonic-gate
14037c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
14047c478bd9Sstevel@tonic-gate
14057c478bd9Sstevel@tonic-gate /*
14067c478bd9Sstevel@tonic-gate * If this connection is closing, don't accept any new messages.
14077c478bd9Sstevel@tonic-gate */
14087c478bd9Sstevel@tonic-gate if (mir->mir_svc_no_more_msgs) {
14097c478bd9Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER);
14107c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
14117c478bd9Sstevel@tonic-gate freemsg(mp);
14127c478bd9Sstevel@tonic-gate return;
14137c478bd9Sstevel@tonic-gate }
14147c478bd9Sstevel@tonic-gate
14157c478bd9Sstevel@tonic-gate /* Get local copies for quicker access. */
14167c478bd9Sstevel@tonic-gate frag_len = mir->mir_frag_len;
14177c478bd9Sstevel@tonic-gate frag_header = mir->mir_frag_header;
14187c478bd9Sstevel@tonic-gate head_mp = mir->mir_head_mp;
14197c478bd9Sstevel@tonic-gate tail_mp = mir->mir_tail_mp;
14207c478bd9Sstevel@tonic-gate
14217c478bd9Sstevel@tonic-gate /* Loop, processing each message block in the mp chain separately. */
14227c478bd9Sstevel@tonic-gate do {
14237c478bd9Sstevel@tonic-gate cont_mp = mp->b_cont;
1424153adbb6Smeem mp->b_cont = NULL;
14257c478bd9Sstevel@tonic-gate
14267c478bd9Sstevel@tonic-gate /*
1427456fcba7Smeem * Drop zero-length mblks to prevent unbounded kernel memory
1428456fcba7Smeem * consumption.
1429456fcba7Smeem */
1430456fcba7Smeem if (MBLKL(mp) == 0) {
1431456fcba7Smeem freeb(mp);
1432456fcba7Smeem continue;
1433456fcba7Smeem }
1434456fcba7Smeem
1435456fcba7Smeem /*
1436153adbb6Smeem * If frag_len is negative, we're still in the process of
1437153adbb6Smeem * building frag_header -- try to complete it with this mblk.
14387c478bd9Sstevel@tonic-gate */
1439153adbb6Smeem while (frag_len < 0 && mp->b_rptr < mp->b_wptr) {
14407c478bd9Sstevel@tonic-gate frag_len++;
14417c478bd9Sstevel@tonic-gate frag_header <<= 8;
1442153adbb6Smeem frag_header += *mp->b_rptr++;
14437c478bd9Sstevel@tonic-gate }
14447c478bd9Sstevel@tonic-gate
1445456fcba7Smeem if (MBLKL(mp) == 0 && frag_len < 0) {
14467c478bd9Sstevel@tonic-gate /*
1447456fcba7Smeem * We consumed this mblk while trying to complete the
1448456fcba7Smeem * fragment header. Free it and move on.
14497c478bd9Sstevel@tonic-gate */
14507c478bd9Sstevel@tonic-gate freeb(mp);
14517c478bd9Sstevel@tonic-gate continue;
14527c478bd9Sstevel@tonic-gate }
1453153adbb6Smeem
1454153adbb6Smeem ASSERT(frag_len >= 0);
14557c478bd9Sstevel@tonic-gate
14567c478bd9Sstevel@tonic-gate /*
1457153adbb6Smeem * Now frag_header has the number of bytes in this fragment
1458153adbb6Smeem * and we're just waiting to collect them all. Chain our
1459153adbb6Smeem * latest mblk onto the list and see if we now have enough
1460153adbb6Smeem * bytes to complete the fragment.
14617c478bd9Sstevel@tonic-gate */
1462153adbb6Smeem if (head_mp == NULL) {
1463153adbb6Smeem ASSERT(tail_mp == NULL);
1464153adbb6Smeem head_mp = tail_mp = mp;
1465153adbb6Smeem } else {
14667c478bd9Sstevel@tonic-gate tail_mp->b_cont = mp;
14677c478bd9Sstevel@tonic-gate tail_mp = mp;
1468153adbb6Smeem }
14697c478bd9Sstevel@tonic-gate
1470153adbb6Smeem frag_len += MBLKL(mp);
14717c478bd9Sstevel@tonic-gate excess = frag_len - (frag_header & ~MIR_LASTFRAG);
1472153adbb6Smeem if (excess < 0) {
14737c478bd9Sstevel@tonic-gate /*
1474153adbb6Smeem * We still haven't received enough data to complete
1475153adbb6Smeem * the fragment, so continue on to the next mblk.
14767c478bd9Sstevel@tonic-gate */
14777c478bd9Sstevel@tonic-gate continue;
14787c478bd9Sstevel@tonic-gate }
14797c478bd9Sstevel@tonic-gate
14807c478bd9Sstevel@tonic-gate /*
1481153adbb6Smeem * We've got a complete fragment. If there are excess bytes,
1482153adbb6Smeem * then they're part of the next fragment's header (of either
1483153adbb6Smeem * this RPC message or the next RPC message). Split that part
1484153adbb6Smeem * into its own mblk so that we can safely freeb() it when
1485153adbb6Smeem * building frag_header above.
14867c478bd9Sstevel@tonic-gate */
14877c478bd9Sstevel@tonic-gate if (excess > 0) {
1488153adbb6Smeem if ((mp1 = dupb(mp)) == NULL &&
1489153adbb6Smeem (mp1 = copyb(mp)) == NULL) {
14907c478bd9Sstevel@tonic-gate freemsg(head_mp);
1491153adbb6Smeem freemsg(cont_mp);
1492153adbb6Smeem RPCLOG0(1, "mir_rput: dupb/copyb failed\n");
14937c478bd9Sstevel@tonic-gate mir->mir_frag_header = 0;
1494153adbb6Smeem mir->mir_frag_len = -(int32_t)sizeof (uint32_t);
14957c478bd9Sstevel@tonic-gate mir->mir_head_mp = NULL;
14967c478bd9Sstevel@tonic-gate mir->mir_tail_mp = NULL;
1497153adbb6Smeem mir_disconnect(q, mir); /* drops mir_mutex */
14987c478bd9Sstevel@tonic-gate return;
14997c478bd9Sstevel@tonic-gate }
15007c478bd9Sstevel@tonic-gate
15017c478bd9Sstevel@tonic-gate /*
1502153adbb6Smeem * Relink the message chain so that the next mblk is
1503153adbb6Smeem * the next fragment header, followed by the rest of
1504153adbb6Smeem * the message chain.
15057c478bd9Sstevel@tonic-gate */
15067c478bd9Sstevel@tonic-gate mp1->b_cont = cont_mp;
15077c478bd9Sstevel@tonic-gate cont_mp = mp1;
1508153adbb6Smeem
15097c478bd9Sstevel@tonic-gate /*
1510153adbb6Smeem * Data in the new mblk begins at the next fragment,
1511153adbb6Smeem * and data in the old mblk ends at the next fragment.
15127c478bd9Sstevel@tonic-gate */
1513153adbb6Smeem mp1->b_rptr = mp1->b_wptr - excess;
1514153adbb6Smeem mp->b_wptr -= excess;
15157c478bd9Sstevel@tonic-gate }
15167c478bd9Sstevel@tonic-gate
1517153adbb6Smeem /*
1518153adbb6Smeem * Reset frag_len and frag_header for the next fragment.
1519153adbb6Smeem */
1520153adbb6Smeem frag_len = -(int32_t)sizeof (uint32_t);
1521153adbb6Smeem if (!(frag_header & MIR_LASTFRAG)) {
1522153adbb6Smeem /*
1523153adbb6Smeem * The current fragment is complete, but more
1524153adbb6Smeem * fragments need to be processed before we can
1525153adbb6Smeem * pass along the RPC message headed at head_mp.
1526153adbb6Smeem */
1527153adbb6Smeem frag_header = 0;
1528153adbb6Smeem continue;
1529153adbb6Smeem }
1530153adbb6Smeem frag_header = 0;
15317c478bd9Sstevel@tonic-gate
1532153adbb6Smeem /*
1533153adbb6Smeem * We've got a complete RPC message; pass it to the
1534153adbb6Smeem * appropriate consumer.
1535153adbb6Smeem */
15367c478bd9Sstevel@tonic-gate switch (mir->mir_type) {
15377c478bd9Sstevel@tonic-gate case RPC_CLIENT:
15387c478bd9Sstevel@tonic-gate if (clnt_dispatch_notify(head_mp, mir->mir_zoneid)) {
15397c478bd9Sstevel@tonic-gate /*
15407c478bd9Sstevel@tonic-gate * Mark this stream as active. This marker
15417c478bd9Sstevel@tonic-gate * is used in mir_timer().
15427c478bd9Sstevel@tonic-gate */
15437c478bd9Sstevel@tonic-gate mir->mir_clntreq = 1;
1544d3d50737SRafael Vanoni mir->mir_use_timestamp = ddi_get_lbolt();
1545153adbb6Smeem } else {
15467c478bd9Sstevel@tonic-gate freemsg(head_mp);
1547153adbb6Smeem }
15487c478bd9Sstevel@tonic-gate break;
15497c478bd9Sstevel@tonic-gate
15507c478bd9Sstevel@tonic-gate case RPC_SERVER:
15517c478bd9Sstevel@tonic-gate /*
15527c478bd9Sstevel@tonic-gate * Check for flow control before passing the
15532695d4f4SMarcel Telka * message to kRPC.
15547c478bd9Sstevel@tonic-gate */
15557c478bd9Sstevel@tonic-gate if (!mir->mir_hold_inbound) {
15567c478bd9Sstevel@tonic-gate if (mir->mir_krpc_cell) {
15572695d4f4SMarcel Telka
1558*3b3b7026SMarcel Telka if (mir_check_len(q, head_mp))
15592695d4f4SMarcel Telka return;
15602695d4f4SMarcel Telka
15612695d4f4SMarcel Telka if (q->q_first == NULL &&
15622695d4f4SMarcel Telka svc_queuereq(q, head_mp, TRUE)) {
15637c478bd9Sstevel@tonic-gate /*
15647c478bd9Sstevel@tonic-gate * If the reference count is 0
15652695d4f4SMarcel Telka * (not including this
15662695d4f4SMarcel Telka * request), then the stream is
15672695d4f4SMarcel Telka * transitioning from idle to
15682695d4f4SMarcel Telka * non-idle. In this case, we
15692695d4f4SMarcel Telka * cancel the idle timer.
15707c478bd9Sstevel@tonic-gate */
15717c478bd9Sstevel@tonic-gate if (mir->mir_ref_cnt++ == 0)
15727c478bd9Sstevel@tonic-gate stop_timer = B_TRUE;
15732695d4f4SMarcel Telka } else {
15742695d4f4SMarcel Telka (void) putq(q, head_mp);
15752695d4f4SMarcel Telka mir->mir_inrservice = B_TRUE;
15762695d4f4SMarcel Telka }
15777c478bd9Sstevel@tonic-gate } else {
15787c478bd9Sstevel@tonic-gate /*
157907e75131Sgt29601 * Count # of times this happens. Should
158007e75131Sgt29601 * be never, but experience shows
158107e75131Sgt29601 * otherwise.
15827c478bd9Sstevel@tonic-gate */
15837c478bd9Sstevel@tonic-gate mir_krpc_cell_null++;
15847c478bd9Sstevel@tonic-gate freemsg(head_mp);
15857c478bd9Sstevel@tonic-gate }
15867c478bd9Sstevel@tonic-gate } else {
15877c478bd9Sstevel@tonic-gate /*
15887c478bd9Sstevel@tonic-gate * If the outbound side of the stream is
15897c478bd9Sstevel@tonic-gate * flow controlled, then hold this message
15907c478bd9Sstevel@tonic-gate * until client catches up. mir_hold_inbound
15917c478bd9Sstevel@tonic-gate * is set in mir_wput and cleared in mir_wsrv.
15927c478bd9Sstevel@tonic-gate */
15937c478bd9Sstevel@tonic-gate (void) putq(q, head_mp);
15947c478bd9Sstevel@tonic-gate mir->mir_inrservice = B_TRUE;
15957c478bd9Sstevel@tonic-gate }
15967c478bd9Sstevel@tonic-gate break;
15977c478bd9Sstevel@tonic-gate default:
15987c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_rput: unknown mir_type %d\n",
15997c478bd9Sstevel@tonic-gate mir->mir_type);
16007c478bd9Sstevel@tonic-gate freemsg(head_mp);
16017c478bd9Sstevel@tonic-gate break;
16027c478bd9Sstevel@tonic-gate }
16037c478bd9Sstevel@tonic-gate
16047c478bd9Sstevel@tonic-gate /*
1605153adbb6Smeem * Reset the chain since we're starting on a new RPC message.
16067c478bd9Sstevel@tonic-gate */
1607153adbb6Smeem head_mp = tail_mp = NULL;
16087c478bd9Sstevel@tonic-gate } while ((mp = cont_mp) != NULL);
16097c478bd9Sstevel@tonic-gate
16107c478bd9Sstevel@tonic-gate /*
1611153adbb6Smeem * Sanity check the message length; if it's too large mir_check_len()
1612153adbb6Smeem * will shutdown the connection, drop mir_mutex, and return non-zero.
16137c478bd9Sstevel@tonic-gate */
16147c478bd9Sstevel@tonic-gate if (head_mp != NULL && mir->mir_setup_complete &&
1615*3b3b7026SMarcel Telka mir_check_len(q, head_mp))
16167c478bd9Sstevel@tonic-gate return;
16177c478bd9Sstevel@tonic-gate
16187c478bd9Sstevel@tonic-gate /* Save our local copies back in the mir structure. */
16197c478bd9Sstevel@tonic-gate mir->mir_frag_header = frag_header;
16207c478bd9Sstevel@tonic-gate mir->mir_frag_len = frag_len;
16217c478bd9Sstevel@tonic-gate mir->mir_head_mp = head_mp;
16227c478bd9Sstevel@tonic-gate mir->mir_tail_mp = tail_mp;
16237c478bd9Sstevel@tonic-gate
16247c478bd9Sstevel@tonic-gate /*
16257c478bd9Sstevel@tonic-gate * The timer is stopped after the whole message chain is processed.
16267c478bd9Sstevel@tonic-gate * The reason is that stopping the timer releases the mir_mutex
16277c478bd9Sstevel@tonic-gate * lock temporarily. This means that the request can be serviced
16287c478bd9Sstevel@tonic-gate * while we are still processing the message chain. This is not
16297c478bd9Sstevel@tonic-gate * good. So we stop the timer here instead.
16307c478bd9Sstevel@tonic-gate *
16317c478bd9Sstevel@tonic-gate * Note that if the timer fires before we stop it, it will not
16327c478bd9Sstevel@tonic-gate * do any harm as MIR_SVC_QUIESCED() is false and mir_timer()
1633153adbb6Smeem * will just return.
16347c478bd9Sstevel@tonic-gate */
16357c478bd9Sstevel@tonic-gate if (stop_timer) {
1636153adbb6Smeem RPCLOG(16, "mir_rput: stopping idle timer on 0x%p because "
16377c478bd9Sstevel@tonic-gate "ref cnt going to non zero\n", (void *)WR(q));
16387c478bd9Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir);
16397c478bd9Sstevel@tonic-gate }
16407c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
16417c478bd9Sstevel@tonic-gate }
16427c478bd9Sstevel@tonic-gate
16437c478bd9Sstevel@tonic-gate static void
mir_rput_proto(queue_t * q,mblk_t * mp)16447c478bd9Sstevel@tonic-gate mir_rput_proto(queue_t *q, mblk_t *mp)
16457c478bd9Sstevel@tonic-gate {
16467c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr;
16477c478bd9Sstevel@tonic-gate uint32_t type;
16487c478bd9Sstevel@tonic-gate uint32_t reason = 0;
16497c478bd9Sstevel@tonic-gate
16507c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
16517c478bd9Sstevel@tonic-gate
16527c478bd9Sstevel@tonic-gate type = ((union T_primitives *)mp->b_rptr)->type;
16537c478bd9Sstevel@tonic-gate switch (mir->mir_type) {
16547c478bd9Sstevel@tonic-gate case RPC_CLIENT:
16557c478bd9Sstevel@tonic-gate switch (type) {
16567c478bd9Sstevel@tonic-gate case T_DISCON_IND:
165707e75131Sgt29601 reason = ((struct T_discon_ind *)
165807e75131Sgt29601 (mp->b_rptr))->DISCON_reason;
16597c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
16607c478bd9Sstevel@tonic-gate case T_ORDREL_IND:
16617c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
16627c478bd9Sstevel@tonic-gate if (mir->mir_head_mp) {
16637c478bd9Sstevel@tonic-gate freemsg(mir->mir_head_mp);
16647c478bd9Sstevel@tonic-gate mir->mir_head_mp = (mblk_t *)0;
16657c478bd9Sstevel@tonic-gate mir->mir_tail_mp = (mblk_t *)0;
16667c478bd9Sstevel@tonic-gate }
16677c478bd9Sstevel@tonic-gate /*
16687c478bd9Sstevel@tonic-gate * We are disconnecting, but not necessarily
16697c478bd9Sstevel@tonic-gate * closing. By not closing, we will fail to
16707c478bd9Sstevel@tonic-gate * pick up a possibly changed global timeout value,
16717c478bd9Sstevel@tonic-gate * unless we store it now.
16727c478bd9Sstevel@tonic-gate */
16737c478bd9Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout;
16747c478bd9Sstevel@tonic-gate mir_clnt_idle_stop(WR(q), mir);
16757c478bd9Sstevel@tonic-gate
16767c478bd9Sstevel@tonic-gate /*
16777c478bd9Sstevel@tonic-gate * Even though we are unconnected, we still
16787c478bd9Sstevel@tonic-gate * leave the idle timer going on the client. The
16797c478bd9Sstevel@tonic-gate * reason for is that if we've disconnected due
16807c478bd9Sstevel@tonic-gate * to a server-side disconnect, reset, or connection
16817c478bd9Sstevel@tonic-gate * timeout, there is a possibility the client may
16827c478bd9Sstevel@tonic-gate * retry the RPC request. This retry needs to done on
16837c478bd9Sstevel@tonic-gate * the same bound address for the server to interpret
16847c478bd9Sstevel@tonic-gate * it as such. However, we don't want
16857c478bd9Sstevel@tonic-gate * to wait forever for that possibility. If the
16867c478bd9Sstevel@tonic-gate * end-point stays unconnected for mir_idle_timeout
16877c478bd9Sstevel@tonic-gate * units of time, then that is a signal to the
16887c478bd9Sstevel@tonic-gate * connection manager to give up waiting for the
16897c478bd9Sstevel@tonic-gate * application (eg. NFS) to send a retry.
16907c478bd9Sstevel@tonic-gate */
16917c478bd9Sstevel@tonic-gate mir_clnt_idle_start(WR(q), mir);
16927c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
16937c478bd9Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), type, reason);
16947c478bd9Sstevel@tonic-gate freemsg(mp);
16957c478bd9Sstevel@tonic-gate return;
16967c478bd9Sstevel@tonic-gate case T_ERROR_ACK:
16977c478bd9Sstevel@tonic-gate {
16987c478bd9Sstevel@tonic-gate struct T_error_ack *terror;
16997c478bd9Sstevel@tonic-gate
17007c478bd9Sstevel@tonic-gate terror = (struct T_error_ack *)mp->b_rptr;
17017c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_rput_proto T_ERROR_ACK for queue 0x%p",
17027c478bd9Sstevel@tonic-gate (void *)q);
17037c478bd9Sstevel@tonic-gate RPCLOG(1, " ERROR_prim: %s,",
17047c478bd9Sstevel@tonic-gate rpc_tpiprim2name(terror->ERROR_prim));
17057c478bd9Sstevel@tonic-gate RPCLOG(1, " TLI_error: %s,",
17067c478bd9Sstevel@tonic-gate rpc_tpierr2name(terror->TLI_error));
17077c478bd9Sstevel@tonic-gate RPCLOG(1, " UNIX_error: %d\n", terror->UNIX_error);
17087c478bd9Sstevel@tonic-gate if (terror->ERROR_prim == T_DISCON_REQ) {
17097c478bd9Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), type, reason);
17107c478bd9Sstevel@tonic-gate freemsg(mp);
17117c478bd9Sstevel@tonic-gate return;
17127c478bd9Sstevel@tonic-gate } else {
17137c478bd9Sstevel@tonic-gate if (clnt_dispatch_notifyconn(WR(q), mp))
17147c478bd9Sstevel@tonic-gate return;
17157c478bd9Sstevel@tonic-gate }
17167c478bd9Sstevel@tonic-gate break;
17177c478bd9Sstevel@tonic-gate }
17187c478bd9Sstevel@tonic-gate case T_OK_ACK:
17197c478bd9Sstevel@tonic-gate {
17207c478bd9Sstevel@tonic-gate struct T_ok_ack *tok = (struct T_ok_ack *)mp->b_rptr;
17217c478bd9Sstevel@tonic-gate
17227c478bd9Sstevel@tonic-gate if (tok->CORRECT_prim == T_DISCON_REQ) {
17237c478bd9Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), type, reason);
17247c478bd9Sstevel@tonic-gate freemsg(mp);
17257c478bd9Sstevel@tonic-gate return;
17267c478bd9Sstevel@tonic-gate } else {
17277c478bd9Sstevel@tonic-gate if (clnt_dispatch_notifyconn(WR(q), mp))
17287c478bd9Sstevel@tonic-gate return;
17297c478bd9Sstevel@tonic-gate }
17307c478bd9Sstevel@tonic-gate break;
17317c478bd9Sstevel@tonic-gate }
17327c478bd9Sstevel@tonic-gate case T_CONN_CON:
17337c478bd9Sstevel@tonic-gate case T_INFO_ACK:
17347c478bd9Sstevel@tonic-gate case T_OPTMGMT_ACK:
17357c478bd9Sstevel@tonic-gate if (clnt_dispatch_notifyconn(WR(q), mp))
17367c478bd9Sstevel@tonic-gate return;
17377c478bd9Sstevel@tonic-gate break;
17387c478bd9Sstevel@tonic-gate case T_BIND_ACK:
17397c478bd9Sstevel@tonic-gate break;
17407c478bd9Sstevel@tonic-gate default:
17417c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_rput: unexpected message %d "
17422695d4f4SMarcel Telka "for kRPC client\n",
17437c478bd9Sstevel@tonic-gate ((union T_primitives *)mp->b_rptr)->type);
17447c478bd9Sstevel@tonic-gate break;
17457c478bd9Sstevel@tonic-gate }
17467c478bd9Sstevel@tonic-gate break;
17477c478bd9Sstevel@tonic-gate
17487c478bd9Sstevel@tonic-gate case RPC_SERVER:
17497c478bd9Sstevel@tonic-gate switch (type) {
17507c478bd9Sstevel@tonic-gate case T_BIND_ACK:
17517c478bd9Sstevel@tonic-gate {
17527c478bd9Sstevel@tonic-gate struct T_bind_ack *tbind;
17537c478bd9Sstevel@tonic-gate
17547c478bd9Sstevel@tonic-gate /*
17557c478bd9Sstevel@tonic-gate * If this is a listening stream, then shut
17567c478bd9Sstevel@tonic-gate * off the idle timer.
17577c478bd9Sstevel@tonic-gate */
17587c478bd9Sstevel@tonic-gate tbind = (struct T_bind_ack *)mp->b_rptr;
17597c478bd9Sstevel@tonic-gate if (tbind->CONIND_number > 0) {
17607c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
17617c478bd9Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir);
17627c478bd9Sstevel@tonic-gate
17637c478bd9Sstevel@tonic-gate /*
17647c478bd9Sstevel@tonic-gate * mark this as a listen endpoint
17657c478bd9Sstevel@tonic-gate * for special handling.
17667c478bd9Sstevel@tonic-gate */
17677c478bd9Sstevel@tonic-gate
17687c478bd9Sstevel@tonic-gate mir->mir_listen_stream = 1;
17697c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
17707c478bd9Sstevel@tonic-gate }
17717c478bd9Sstevel@tonic-gate break;
17727c478bd9Sstevel@tonic-gate }
17737c478bd9Sstevel@tonic-gate case T_DISCON_IND:
17747c478bd9Sstevel@tonic-gate case T_ORDREL_IND:
17757c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: got %s indication\n",
17767c478bd9Sstevel@tonic-gate type == T_DISCON_IND ? "disconnect"
17777c478bd9Sstevel@tonic-gate : "orderly release");
17787c478bd9Sstevel@tonic-gate
17797c478bd9Sstevel@tonic-gate /*
17807c478bd9Sstevel@tonic-gate * For listen endpoint just pass
17817c478bd9Sstevel@tonic-gate * on the message.
17827c478bd9Sstevel@tonic-gate */
17837c478bd9Sstevel@tonic-gate
17847c478bd9Sstevel@tonic-gate if (mir->mir_listen_stream)
17857c478bd9Sstevel@tonic-gate break;
17867c478bd9Sstevel@tonic-gate
17877c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
17887c478bd9Sstevel@tonic-gate
17897c478bd9Sstevel@tonic-gate /*
17907c478bd9Sstevel@tonic-gate * If client wants to break off connection, record
17917c478bd9Sstevel@tonic-gate * that fact.
17927c478bd9Sstevel@tonic-gate */
17937c478bd9Sstevel@tonic-gate mir_svc_start_close(WR(q), mir);
17947c478bd9Sstevel@tonic-gate
17957c478bd9Sstevel@tonic-gate /*
17967c478bd9Sstevel@tonic-gate * If we are idle, then send the orderly release
17977c478bd9Sstevel@tonic-gate * or disconnect indication to nfsd.
17987c478bd9Sstevel@tonic-gate */
17997c478bd9Sstevel@tonic-gate if (MIR_SVC_QUIESCED(mir)) {
18007c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
18017c478bd9Sstevel@tonic-gate break;
18027c478bd9Sstevel@tonic-gate }
18037c478bd9Sstevel@tonic-gate
18047c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: not idle, so "
18057c478bd9Sstevel@tonic-gate "disconnect/ord rel indication not passed "
18067c478bd9Sstevel@tonic-gate "upstream on 0x%p\n", (void *)q);
18077c478bd9Sstevel@tonic-gate
18087c478bd9Sstevel@tonic-gate /*
18097c478bd9Sstevel@tonic-gate * Hold the indication until we get idle
18107c478bd9Sstevel@tonic-gate * If there already is an indication stored,
18117c478bd9Sstevel@tonic-gate * replace it if the new one is a disconnect. The
18127c478bd9Sstevel@tonic-gate * reasoning is that disconnection takes less time
18137c478bd9Sstevel@tonic-gate * to process, and once a client decides to
18147c478bd9Sstevel@tonic-gate * disconnect, we should do that.
18157c478bd9Sstevel@tonic-gate */
18167c478bd9Sstevel@tonic-gate if (mir->mir_svc_pend_mp) {
18177c478bd9Sstevel@tonic-gate if (type == T_DISCON_IND) {
18187c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: replacing"
18197c478bd9Sstevel@tonic-gate " held disconnect/ord rel"
18207c478bd9Sstevel@tonic-gate " indication with disconnect on"
18217c478bd9Sstevel@tonic-gate " 0x%p\n", (void *)q);
18227c478bd9Sstevel@tonic-gate
18237c478bd9Sstevel@tonic-gate freemsg(mir->mir_svc_pend_mp);
18247c478bd9Sstevel@tonic-gate mir->mir_svc_pend_mp = mp;
18257c478bd9Sstevel@tonic-gate } else {
18267c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_rput_proto: already "
18277c478bd9Sstevel@tonic-gate "held a disconnect/ord rel "
18287c478bd9Sstevel@tonic-gate "indication. freeing ord rel "
18297c478bd9Sstevel@tonic-gate "ind on 0x%p\n", (void *)q);
18307c478bd9Sstevel@tonic-gate freemsg(mp);
18317c478bd9Sstevel@tonic-gate }
18327c478bd9Sstevel@tonic-gate } else
18337c478bd9Sstevel@tonic-gate mir->mir_svc_pend_mp = mp;
18347c478bd9Sstevel@tonic-gate
18357c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
18367c478bd9Sstevel@tonic-gate return;
18377c478bd9Sstevel@tonic-gate
18387c478bd9Sstevel@tonic-gate default:
18397c478bd9Sstevel@tonic-gate /* nfsd handles server-side non-data messages. */
18407c478bd9Sstevel@tonic-gate break;
18417c478bd9Sstevel@tonic-gate }
18427c478bd9Sstevel@tonic-gate break;
18437c478bd9Sstevel@tonic-gate
18447c478bd9Sstevel@tonic-gate default:
18457c478bd9Sstevel@tonic-gate break;
18467c478bd9Sstevel@tonic-gate }
18477c478bd9Sstevel@tonic-gate
18487c478bd9Sstevel@tonic-gate putnext(q, mp);
18497c478bd9Sstevel@tonic-gate }
18507c478bd9Sstevel@tonic-gate
18517c478bd9Sstevel@tonic-gate /*
18527c478bd9Sstevel@tonic-gate * The server-side read queues are used to hold inbound messages while
18537c478bd9Sstevel@tonic-gate * outbound flow control is exerted. When outbound flow control is
18547c478bd9Sstevel@tonic-gate * relieved, mir_wsrv qenables the read-side queue. Read-side queues
18557c478bd9Sstevel@tonic-gate * are not enabled by STREAMS and are explicitly noenable'ed in mir_open.
18567c478bd9Sstevel@tonic-gate */
18577c478bd9Sstevel@tonic-gate static void
mir_rsrv(queue_t * q)18587c478bd9Sstevel@tonic-gate mir_rsrv(queue_t *q)
18597c478bd9Sstevel@tonic-gate {
18607c478bd9Sstevel@tonic-gate mir_t *mir;
18617c478bd9Sstevel@tonic-gate mblk_t *mp;
18627c478bd9Sstevel@tonic-gate boolean_t stop_timer = B_FALSE;
18637c478bd9Sstevel@tonic-gate
18647c478bd9Sstevel@tonic-gate mir = (mir_t *)q->q_ptr;
18657c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
18667c478bd9Sstevel@tonic-gate
18677c478bd9Sstevel@tonic-gate mp = NULL;
18687c478bd9Sstevel@tonic-gate switch (mir->mir_type) {
18697c478bd9Sstevel@tonic-gate case RPC_SERVER:
18707c478bd9Sstevel@tonic-gate if (mir->mir_ref_cnt == 0)
18717c478bd9Sstevel@tonic-gate mir->mir_hold_inbound = 0;
18722695d4f4SMarcel Telka if (mir->mir_hold_inbound)
18732695d4f4SMarcel Telka break;
18747c478bd9Sstevel@tonic-gate
18757c478bd9Sstevel@tonic-gate while (mp = getq(q)) {
187607e75131Sgt29601 if (mir->mir_krpc_cell &&
187707e75131Sgt29601 (mir->mir_svc_no_more_msgs == 0)) {
18782695d4f4SMarcel Telka
1879*3b3b7026SMarcel Telka if (mir_check_len(q, mp))
18807c478bd9Sstevel@tonic-gate return;
18812695d4f4SMarcel Telka
18822695d4f4SMarcel Telka if (svc_queuereq(q, mp, TRUE)) {
18832695d4f4SMarcel Telka /*
18842695d4f4SMarcel Telka * If we were idle, turn off idle timer
18852695d4f4SMarcel Telka * since we aren't idle any more.
18862695d4f4SMarcel Telka */
18872695d4f4SMarcel Telka if (mir->mir_ref_cnt++ == 0)
18882695d4f4SMarcel Telka stop_timer = B_TRUE;
18892695d4f4SMarcel Telka } else {
18902695d4f4SMarcel Telka (void) putbq(q, mp);
18912695d4f4SMarcel Telka break;
18922695d4f4SMarcel Telka }
18937c478bd9Sstevel@tonic-gate } else {
18947c478bd9Sstevel@tonic-gate /*
18957c478bd9Sstevel@tonic-gate * Count # of times this happens. Should be
18967c478bd9Sstevel@tonic-gate * never, but experience shows otherwise.
18977c478bd9Sstevel@tonic-gate */
189807e75131Sgt29601 if (mir->mir_krpc_cell == NULL)
18997c478bd9Sstevel@tonic-gate mir_krpc_cell_null++;
19007c478bd9Sstevel@tonic-gate freemsg(mp);
19017c478bd9Sstevel@tonic-gate }
19027c478bd9Sstevel@tonic-gate }
19037c478bd9Sstevel@tonic-gate break;
19047c478bd9Sstevel@tonic-gate case RPC_CLIENT:
19057c478bd9Sstevel@tonic-gate break;
19067c478bd9Sstevel@tonic-gate default:
19077c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_rsrv: unexpected mir_type %d\n", mir->mir_type);
19087c478bd9Sstevel@tonic-gate
19097c478bd9Sstevel@tonic-gate if (q->q_first == NULL)
19107c478bd9Sstevel@tonic-gate MIR_CLEAR_INRSRV(mir);
19117c478bd9Sstevel@tonic-gate
19127c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
19137c478bd9Sstevel@tonic-gate
19147c478bd9Sstevel@tonic-gate return;
19157c478bd9Sstevel@tonic-gate }
19167c478bd9Sstevel@tonic-gate
19177c478bd9Sstevel@tonic-gate /*
19187c478bd9Sstevel@tonic-gate * The timer is stopped after all the messages are processed.
19197c478bd9Sstevel@tonic-gate * The reason is that stopping the timer releases the mir_mutex
19207c478bd9Sstevel@tonic-gate * lock temporarily. This means that the request can be serviced
19217c478bd9Sstevel@tonic-gate * while we are still processing the message queue. This is not
19227c478bd9Sstevel@tonic-gate * good. So we stop the timer here instead.
19237c478bd9Sstevel@tonic-gate */
19247c478bd9Sstevel@tonic-gate if (stop_timer) {
19257c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_rsrv stopping idle timer on 0x%p because ref "
19267c478bd9Sstevel@tonic-gate "cnt going to non zero\n", (void *)WR(q));
19277c478bd9Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir);
19287c478bd9Sstevel@tonic-gate }
19297c478bd9Sstevel@tonic-gate
19307c478bd9Sstevel@tonic-gate if (q->q_first == NULL) {
19312695d4f4SMarcel Telka mblk_t *cmp = NULL;
19327c478bd9Sstevel@tonic-gate
19337c478bd9Sstevel@tonic-gate MIR_CLEAR_INRSRV(mir);
19347c478bd9Sstevel@tonic-gate
19357c478bd9Sstevel@tonic-gate if (mir->mir_type == RPC_SERVER && MIR_SVC_QUIESCED(mir)) {
19367c478bd9Sstevel@tonic-gate cmp = mir->mir_svc_pend_mp;
19377c478bd9Sstevel@tonic-gate mir->mir_svc_pend_mp = NULL;
19387c478bd9Sstevel@tonic-gate }
19397c478bd9Sstevel@tonic-gate
19407c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
19417c478bd9Sstevel@tonic-gate
19427c478bd9Sstevel@tonic-gate if (cmp != NULL) {
19437c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_rsrv: line %d: sending a held "
19447c478bd9Sstevel@tonic-gate "disconnect/ord rel indication upstream\n",
19457c478bd9Sstevel@tonic-gate __LINE__);
19467c478bd9Sstevel@tonic-gate putnext(q, cmp);
19477c478bd9Sstevel@tonic-gate }
19487c478bd9Sstevel@tonic-gate
19497c478bd9Sstevel@tonic-gate return;
19507c478bd9Sstevel@tonic-gate }
19517c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
19527c478bd9Sstevel@tonic-gate }
19537c478bd9Sstevel@tonic-gate
19547c478bd9Sstevel@tonic-gate static int mir_svc_policy_fails;
19557c478bd9Sstevel@tonic-gate
19567c478bd9Sstevel@tonic-gate /*
19577c478bd9Sstevel@tonic-gate * Called to send an event code to nfsd/lockd so that it initiates
19587c478bd9Sstevel@tonic-gate * connection close.
19597c478bd9Sstevel@tonic-gate */
19607c478bd9Sstevel@tonic-gate static int
mir_svc_policy_notify(queue_t * q,int event)19617c478bd9Sstevel@tonic-gate mir_svc_policy_notify(queue_t *q, int event)
19627c478bd9Sstevel@tonic-gate {
19637c478bd9Sstevel@tonic-gate mblk_t *mp;
19647c478bd9Sstevel@tonic-gate #ifdef DEBUG
19657c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr;
19667c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
19677c478bd9Sstevel@tonic-gate #endif
19687c478bd9Sstevel@tonic-gate ASSERT(q->q_flag & QREADR);
19697c478bd9Sstevel@tonic-gate
19707c478bd9Sstevel@tonic-gate /*
19717c478bd9Sstevel@tonic-gate * Create an M_DATA message with the event code and pass it to the
19727c478bd9Sstevel@tonic-gate * Stream head (nfsd or whoever created the stream will consume it).
19737c478bd9Sstevel@tonic-gate */
19747c478bd9Sstevel@tonic-gate mp = allocb(sizeof (int), BPRI_HI);
19757c478bd9Sstevel@tonic-gate
19767c478bd9Sstevel@tonic-gate if (!mp) {
19777c478bd9Sstevel@tonic-gate
19787c478bd9Sstevel@tonic-gate mir_svc_policy_fails++;
19797c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_svc_policy_notify: could not allocate event "
19807c478bd9Sstevel@tonic-gate "%d\n", event);
19817c478bd9Sstevel@tonic-gate return (ENOMEM);
19827c478bd9Sstevel@tonic-gate }
19837c478bd9Sstevel@tonic-gate
19847c478bd9Sstevel@tonic-gate U32_TO_BE32(event, mp->b_rptr);
19857c478bd9Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (int);
19867c478bd9Sstevel@tonic-gate putnext(q, mp);
19877c478bd9Sstevel@tonic-gate return (0);
19887c478bd9Sstevel@tonic-gate }
19897c478bd9Sstevel@tonic-gate
19907c478bd9Sstevel@tonic-gate /*
19917c478bd9Sstevel@tonic-gate * Server side: start the close phase. We want to get this rpcmod slot in an
19927c478bd9Sstevel@tonic-gate * idle state before mir_close() is called.
19937c478bd9Sstevel@tonic-gate */
19947c478bd9Sstevel@tonic-gate static void
mir_svc_start_close(queue_t * wq,mir_t * mir)19957c478bd9Sstevel@tonic-gate mir_svc_start_close(queue_t *wq, mir_t *mir)
19967c478bd9Sstevel@tonic-gate {
19977c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
19987c478bd9Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0);
19997c478bd9Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_SERVER);
20007c478bd9Sstevel@tonic-gate
20017c478bd9Sstevel@tonic-gate /*
20027c478bd9Sstevel@tonic-gate * Do not accept any more messages.
20037c478bd9Sstevel@tonic-gate */
20047c478bd9Sstevel@tonic-gate mir->mir_svc_no_more_msgs = 1;
20057c478bd9Sstevel@tonic-gate
20067c478bd9Sstevel@tonic-gate /*
20072695d4f4SMarcel Telka * Next two statements will make the read service procedure
20082695d4f4SMarcel Telka * free everything stuck in the streams read queue.
20097c478bd9Sstevel@tonic-gate * It's not necessary because enabling the write queue will
20107c478bd9Sstevel@tonic-gate * have the same effect, but why not speed the process along?
20117c478bd9Sstevel@tonic-gate */
20127c478bd9Sstevel@tonic-gate mir->mir_hold_inbound = 0;
20137c478bd9Sstevel@tonic-gate qenable(RD(wq));
20147c478bd9Sstevel@tonic-gate
20157c478bd9Sstevel@tonic-gate /*
20167c478bd9Sstevel@tonic-gate * Meanwhile force the write service procedure to send the
20177c478bd9Sstevel@tonic-gate * responses downstream, regardless of flow control.
20187c478bd9Sstevel@tonic-gate */
20197c478bd9Sstevel@tonic-gate qenable(wq);
20207c478bd9Sstevel@tonic-gate }
20217c478bd9Sstevel@tonic-gate
20227c478bd9Sstevel@tonic-gate /*
20232695d4f4SMarcel Telka * This routine is called directly by kRPC after a request is completed,
20247c478bd9Sstevel@tonic-gate * whether a reply was sent or the request was dropped.
20257c478bd9Sstevel@tonic-gate */
20267c478bd9Sstevel@tonic-gate static void
mir_svc_release(queue_t * wq,mblk_t * mp,bool_t enable)20272695d4f4SMarcel Telka mir_svc_release(queue_t *wq, mblk_t *mp, bool_t enable)
20287c478bd9Sstevel@tonic-gate {
20297c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr;
20307c478bd9Sstevel@tonic-gate mblk_t *cmp = NULL;
20317c478bd9Sstevel@tonic-gate
20327c478bd9Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0);
20337c478bd9Sstevel@tonic-gate if (mp)
20347c478bd9Sstevel@tonic-gate freemsg(mp);
20357c478bd9Sstevel@tonic-gate
20362695d4f4SMarcel Telka if (enable)
20372695d4f4SMarcel Telka qenable(RD(wq));
20382695d4f4SMarcel Telka
20397c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
20407c478bd9Sstevel@tonic-gate
20417c478bd9Sstevel@tonic-gate /*
20427c478bd9Sstevel@tonic-gate * Start idle processing if this is the last reference.
20437c478bd9Sstevel@tonic-gate */
204493132ae0Smaheshvs if ((mir->mir_ref_cnt == 1) && (mir->mir_inrservice == 0)) {
2045471fb14eSMarcel Telka cmp = mir->mir_svc_pend_mp;
2046471fb14eSMarcel Telka mir->mir_svc_pend_mp = NULL;
2047471fb14eSMarcel Telka }
2048471fb14eSMarcel Telka
2049471fb14eSMarcel Telka if (cmp) {
2050471fb14eSMarcel Telka RPCLOG(16, "mir_svc_release: sending a held "
2051471fb14eSMarcel Telka "disconnect/ord rel indication upstream on queue 0x%p\n",
2052471fb14eSMarcel Telka (void *)RD(wq));
2053471fb14eSMarcel Telka
2054471fb14eSMarcel Telka mutex_exit(&mir->mir_mutex);
2055471fb14eSMarcel Telka
2056471fb14eSMarcel Telka putnext(RD(wq), cmp);
2057471fb14eSMarcel Telka
2058471fb14eSMarcel Telka mutex_enter(&mir->mir_mutex);
2059471fb14eSMarcel Telka }
2060471fb14eSMarcel Telka
2061471fb14eSMarcel Telka /*
2062471fb14eSMarcel Telka * Start idle processing if this is the last reference.
2063471fb14eSMarcel Telka */
2064471fb14eSMarcel Telka if (mir->mir_ref_cnt == 1 && mir->mir_inrservice == 0) {
20657c478bd9Sstevel@tonic-gate
20667c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_svc_release starting idle timer on 0x%p "
20677c478bd9Sstevel@tonic-gate "because ref cnt is zero\n", (void *) wq);
20687c478bd9Sstevel@tonic-gate
20697c478bd9Sstevel@tonic-gate mir_svc_idle_start(wq, mir);
20707c478bd9Sstevel@tonic-gate }
20717c478bd9Sstevel@tonic-gate
207293132ae0Smaheshvs mir->mir_ref_cnt--;
207393132ae0Smaheshvs ASSERT(mir->mir_ref_cnt >= 0);
207493132ae0Smaheshvs
207593132ae0Smaheshvs /*
207693132ae0Smaheshvs * Wake up the thread waiting to close.
207793132ae0Smaheshvs */
207893132ae0Smaheshvs
207993132ae0Smaheshvs if ((mir->mir_ref_cnt == 0) && mir->mir_closing)
208093132ae0Smaheshvs cv_signal(&mir->mir_condvar);
208193132ae0Smaheshvs
20827c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
20837c478bd9Sstevel@tonic-gate }
20847c478bd9Sstevel@tonic-gate
20857c478bd9Sstevel@tonic-gate /*
20862695d4f4SMarcel Telka * This routine is called by server-side kRPC when it is ready to
20877c478bd9Sstevel@tonic-gate * handle inbound messages on the stream.
20887c478bd9Sstevel@tonic-gate */
20897c478bd9Sstevel@tonic-gate static void
mir_svc_start(queue_t * wq)20907c478bd9Sstevel@tonic-gate mir_svc_start(queue_t *wq)
20917c478bd9Sstevel@tonic-gate {
20927c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr;
20937c478bd9Sstevel@tonic-gate
2094a26eed27Sgt29601 /*
2095a26eed27Sgt29601 * no longer need to take the mir_mutex because the
2096a26eed27Sgt29601 * mir_setup_complete field has been moved out of
2097a26eed27Sgt29601 * the binary field protected by the mir_mutex.
2098a26eed27Sgt29601 */
2099a26eed27Sgt29601
21007c478bd9Sstevel@tonic-gate mir->mir_setup_complete = 1;
21017c478bd9Sstevel@tonic-gate qenable(RD(wq));
21027c478bd9Sstevel@tonic-gate }
21037c478bd9Sstevel@tonic-gate
21047c478bd9Sstevel@tonic-gate /*
21057c478bd9Sstevel@tonic-gate * client side wrapper for stopping timer with normal idle timeout.
21067c478bd9Sstevel@tonic-gate */
21077c478bd9Sstevel@tonic-gate static void
mir_clnt_idle_stop(queue_t * wq,mir_t * mir)21087c478bd9Sstevel@tonic-gate mir_clnt_idle_stop(queue_t *wq, mir_t *mir)
21097c478bd9Sstevel@tonic-gate {
21107c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
21117c478bd9Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0);
21127c478bd9Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_CLIENT);
21137c478bd9Sstevel@tonic-gate
21147c478bd9Sstevel@tonic-gate mir_timer_stop(mir);
21157c478bd9Sstevel@tonic-gate }
21167c478bd9Sstevel@tonic-gate
21177c478bd9Sstevel@tonic-gate /*
21187c478bd9Sstevel@tonic-gate * client side wrapper for stopping timer with normal idle timeout.
21197c478bd9Sstevel@tonic-gate */
21207c478bd9Sstevel@tonic-gate static void
mir_clnt_idle_start(queue_t * wq,mir_t * mir)21217c478bd9Sstevel@tonic-gate mir_clnt_idle_start(queue_t *wq, mir_t *mir)
21227c478bd9Sstevel@tonic-gate {
21237c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
21247c478bd9Sstevel@tonic-gate ASSERT((wq->q_flag & QREADR) == 0);
21257c478bd9Sstevel@tonic-gate ASSERT(mir->mir_type == RPC_CLIENT);
21267c478bd9Sstevel@tonic-gate
21277c478bd9Sstevel@tonic-gate mir_timer_start(wq, mir, mir->mir_idle_timeout);
21287c478bd9Sstevel@tonic-gate }
21297c478bd9Sstevel@tonic-gate
21307c478bd9Sstevel@tonic-gate /*
21317c478bd9Sstevel@tonic-gate * client side only. Forces rpcmod to stop sending T_ORDREL_REQs on
21327c478bd9Sstevel@tonic-gate * end-points that aren't connected.
21337c478bd9Sstevel@tonic-gate */
21347c478bd9Sstevel@tonic-gate static void
mir_clnt_idle_do_stop(queue_t * wq)21357c478bd9Sstevel@tonic-gate mir_clnt_idle_do_stop(queue_t *wq)
21367c478bd9Sstevel@tonic-gate {
21377c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr;
21387c478bd9Sstevel@tonic-gate
21397c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_clnt_idle_do_stop: wq 0x%p\n", (void *)wq);
21407c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
21417c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
21427c478bd9Sstevel@tonic-gate mir_clnt_idle_stop(wq, mir);
21437c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
21447c478bd9Sstevel@tonic-gate }
21457c478bd9Sstevel@tonic-gate
21467c478bd9Sstevel@tonic-gate /*
21477c478bd9Sstevel@tonic-gate * Timer handler. It handles idle timeout and memory shortage problem.
21487c478bd9Sstevel@tonic-gate */
21497c478bd9Sstevel@tonic-gate static void
mir_timer(void * arg)21507c478bd9Sstevel@tonic-gate mir_timer(void *arg)
21517c478bd9Sstevel@tonic-gate {
21527c478bd9Sstevel@tonic-gate queue_t *wq = (queue_t *)arg;
21537c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)wq->q_ptr;
21547c478bd9Sstevel@tonic-gate boolean_t notify;
2155d3d50737SRafael Vanoni clock_t now;
21567c478bd9Sstevel@tonic-gate
21577c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
21587c478bd9Sstevel@tonic-gate
21597c478bd9Sstevel@tonic-gate /*
21607c478bd9Sstevel@tonic-gate * mir_timer_call is set only when either mir_timer_[start|stop]
21617c478bd9Sstevel@tonic-gate * is progressing. And mir_timer() can only be run while they
21627c478bd9Sstevel@tonic-gate * are progressing if the timer is being stopped. So just
21637c478bd9Sstevel@tonic-gate * return.
21647c478bd9Sstevel@tonic-gate */
21657c478bd9Sstevel@tonic-gate if (mir->mir_timer_call) {
21667c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
21677c478bd9Sstevel@tonic-gate return;
21687c478bd9Sstevel@tonic-gate }
21697c478bd9Sstevel@tonic-gate mir->mir_timer_id = 0;
21707c478bd9Sstevel@tonic-gate
21717c478bd9Sstevel@tonic-gate switch (mir->mir_type) {
21727c478bd9Sstevel@tonic-gate case RPC_CLIENT:
21737c478bd9Sstevel@tonic-gate
21747c478bd9Sstevel@tonic-gate /*
21757c478bd9Sstevel@tonic-gate * For clients, the timer fires at clnt_idle_timeout
21767c478bd9Sstevel@tonic-gate * intervals. If the activity marker (mir_clntreq) is
21777c478bd9Sstevel@tonic-gate * zero, then the stream has been idle since the last
21782695d4f4SMarcel Telka * timer event and we notify kRPC. If mir_clntreq is
21797c478bd9Sstevel@tonic-gate * non-zero, then the stream is active and we just
21807c478bd9Sstevel@tonic-gate * restart the timer for another interval. mir_clntreq
21817c478bd9Sstevel@tonic-gate * is set to 1 in mir_wput for every request passed
21827c478bd9Sstevel@tonic-gate * downstream.
21837c478bd9Sstevel@tonic-gate *
21847c478bd9Sstevel@tonic-gate * If this was a memory shortage timer reset the idle
21857c478bd9Sstevel@tonic-gate * timeout regardless; the mir_clntreq will not be a
21867c478bd9Sstevel@tonic-gate * valid indicator.
21877c478bd9Sstevel@tonic-gate *
21887c478bd9Sstevel@tonic-gate * The timer is initially started in mir_wput during
21897c478bd9Sstevel@tonic-gate * RPC_CLIENT ioctl processing.
21907c478bd9Sstevel@tonic-gate *
21917c478bd9Sstevel@tonic-gate * The timer interval can be changed for individual
21927c478bd9Sstevel@tonic-gate * streams with the ND variable "mir_idle_timeout".
21937c478bd9Sstevel@tonic-gate */
2194d3d50737SRafael Vanoni now = ddi_get_lbolt();
21957c478bd9Sstevel@tonic-gate if (mir->mir_clntreq > 0 && mir->mir_use_timestamp +
2196d3d50737SRafael Vanoni MSEC_TO_TICK(mir->mir_idle_timeout) - now >= 0) {
21977c478bd9Sstevel@tonic-gate clock_t tout;
21987c478bd9Sstevel@tonic-gate
21997c478bd9Sstevel@tonic-gate tout = mir->mir_idle_timeout -
2200d3d50737SRafael Vanoni TICK_TO_MSEC(now - mir->mir_use_timestamp);
22017c478bd9Sstevel@tonic-gate if (tout < 0)
22027c478bd9Sstevel@tonic-gate tout = 1000;
22037c478bd9Sstevel@tonic-gate #if 0
220407e75131Sgt29601 printf("mir_timer[%d < %d + %d]: reset client timer "
2205d3d50737SRafael Vanoni "to %d (ms)\n", TICK_TO_MSEC(now),
220607e75131Sgt29601 TICK_TO_MSEC(mir->mir_use_timestamp),
22077c478bd9Sstevel@tonic-gate mir->mir_idle_timeout, tout);
22087c478bd9Sstevel@tonic-gate #endif
22097c478bd9Sstevel@tonic-gate mir->mir_clntreq = 0;
22107c478bd9Sstevel@tonic-gate mir_timer_start(wq, mir, tout);
22117c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
22127c478bd9Sstevel@tonic-gate return;
22137c478bd9Sstevel@tonic-gate }
22147c478bd9Sstevel@tonic-gate #if 0
2215d3d50737SRafael Vanoni printf("mir_timer[%d]: doing client timeout\n", now / hz);
22167c478bd9Sstevel@tonic-gate #endif
22177c478bd9Sstevel@tonic-gate /*
22187c478bd9Sstevel@tonic-gate * We are disconnecting, but not necessarily
22197c478bd9Sstevel@tonic-gate * closing. By not closing, we will fail to
22207c478bd9Sstevel@tonic-gate * pick up a possibly changed global timeout value,
22217c478bd9Sstevel@tonic-gate * unless we store it now.
22227c478bd9Sstevel@tonic-gate */
22237c478bd9Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout;
22247c478bd9Sstevel@tonic-gate mir_clnt_idle_start(wq, mir);
22257c478bd9Sstevel@tonic-gate
22267c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
22277c478bd9Sstevel@tonic-gate /*
22287c478bd9Sstevel@tonic-gate * We pass T_ORDREL_REQ as an integer value
22292695d4f4SMarcel Telka * to kRPC as the indication that the stream
22307c478bd9Sstevel@tonic-gate * is idle. This is not a T_ORDREL_REQ message,
22317c478bd9Sstevel@tonic-gate * it is just a convenient value since we call
22322695d4f4SMarcel Telka * the same kRPC routine for T_ORDREL_INDs and
22337c478bd9Sstevel@tonic-gate * T_DISCON_INDs.
22347c478bd9Sstevel@tonic-gate */
22357c478bd9Sstevel@tonic-gate clnt_dispatch_notifyall(wq, T_ORDREL_REQ, 0);
22367c478bd9Sstevel@tonic-gate return;
22377c478bd9Sstevel@tonic-gate
22387c478bd9Sstevel@tonic-gate case RPC_SERVER:
22397c478bd9Sstevel@tonic-gate
22407c478bd9Sstevel@tonic-gate /*
22417c478bd9Sstevel@tonic-gate * For servers, the timer is only running when the stream
22427c478bd9Sstevel@tonic-gate * is really idle or memory is short. The timer is started
22437c478bd9Sstevel@tonic-gate * by mir_wput when mir_type is set to RPC_SERVER and
22447c478bd9Sstevel@tonic-gate * by mir_svc_idle_start whenever the stream goes idle
22457c478bd9Sstevel@tonic-gate * (mir_ref_cnt == 0). The timer is cancelled in
22462695d4f4SMarcel Telka * mir_rput whenever a new inbound request is passed to kRPC
22477c478bd9Sstevel@tonic-gate * and the stream was previously idle.
22487c478bd9Sstevel@tonic-gate *
22497c478bd9Sstevel@tonic-gate * The timer interval can be changed for individual
22507c478bd9Sstevel@tonic-gate * streams with the ND variable "mir_idle_timeout".
22517c478bd9Sstevel@tonic-gate *
22527c478bd9Sstevel@tonic-gate * If the stream is not idle do nothing.
22537c478bd9Sstevel@tonic-gate */
22547c478bd9Sstevel@tonic-gate if (!MIR_SVC_QUIESCED(mir)) {
22557c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
22567c478bd9Sstevel@tonic-gate return;
22577c478bd9Sstevel@tonic-gate }
22587c478bd9Sstevel@tonic-gate
22597c478bd9Sstevel@tonic-gate notify = !mir->mir_inrservice;
22607c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
22617c478bd9Sstevel@tonic-gate
22627c478bd9Sstevel@tonic-gate /*
22637c478bd9Sstevel@tonic-gate * If there is no packet queued up in read queue, the stream
22647c478bd9Sstevel@tonic-gate * is really idle so notify nfsd to close it.
22657c478bd9Sstevel@tonic-gate */
22667c478bd9Sstevel@tonic-gate if (notify) {
22677c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_timer: telling stream head listener "
22687c478bd9Sstevel@tonic-gate "to close stream (0x%p)\n", (void *) RD(wq));
22697c478bd9Sstevel@tonic-gate (void) mir_svc_policy_notify(RD(wq), 1);
22707c478bd9Sstevel@tonic-gate }
22717c478bd9Sstevel@tonic-gate return;
22727c478bd9Sstevel@tonic-gate default:
22737c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_timer: unexpected mir_type %d\n",
22747c478bd9Sstevel@tonic-gate mir->mir_type);
22757c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
22767c478bd9Sstevel@tonic-gate return;
22777c478bd9Sstevel@tonic-gate }
22787c478bd9Sstevel@tonic-gate }
22797c478bd9Sstevel@tonic-gate
22807c478bd9Sstevel@tonic-gate /*
22817c478bd9Sstevel@tonic-gate * Called by the RPC package to send either a call or a return, or a
22827c478bd9Sstevel@tonic-gate * transport connection request. Adds the record marking header.
22837c478bd9Sstevel@tonic-gate */
22847c478bd9Sstevel@tonic-gate static void
mir_wput(queue_t * q,mblk_t * mp)22857c478bd9Sstevel@tonic-gate mir_wput(queue_t *q, mblk_t *mp)
22867c478bd9Sstevel@tonic-gate {
22877c478bd9Sstevel@tonic-gate uint_t frag_header;
22887c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr;
22897c478bd9Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr;
22907c478bd9Sstevel@tonic-gate
22917c478bd9Sstevel@tonic-gate if (!mir) {
22927c478bd9Sstevel@tonic-gate freemsg(mp);
22937c478bd9Sstevel@tonic-gate return;
22947c478bd9Sstevel@tonic-gate }
22957c478bd9Sstevel@tonic-gate
22967c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type != M_DATA) {
22977c478bd9Sstevel@tonic-gate mir_wput_other(q, mp);
22987c478bd9Sstevel@tonic-gate return;
22997c478bd9Sstevel@tonic-gate }
23007c478bd9Sstevel@tonic-gate
23017c478bd9Sstevel@tonic-gate if (mir->mir_ordrel_pending == 1) {
23027c478bd9Sstevel@tonic-gate freemsg(mp);
23037c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wput wq 0x%p: got data after T_ORDREL_REQ\n",
23047c478bd9Sstevel@tonic-gate (void *)q);
23057c478bd9Sstevel@tonic-gate return;
23067c478bd9Sstevel@tonic-gate }
23077c478bd9Sstevel@tonic-gate
23087c478bd9Sstevel@tonic-gate frag_header = (uint_t)DLEN(mp);
23097c478bd9Sstevel@tonic-gate frag_header |= MIR_LASTFRAG;
23107c478bd9Sstevel@tonic-gate
23117c478bd9Sstevel@tonic-gate /* Stick in the 4 byte record marking header. */
23127c478bd9Sstevel@tonic-gate if ((rptr - mp->b_datap->db_base) < sizeof (uint32_t) ||
23137c478bd9Sstevel@tonic-gate !IS_P2ALIGNED(mp->b_rptr, sizeof (uint32_t))) {
23147c478bd9Sstevel@tonic-gate /*
23157c478bd9Sstevel@tonic-gate * Since we know that M_DATA messages are created exclusively
23162695d4f4SMarcel Telka * by kRPC, we expect that kRPC will leave room for our header
23177c478bd9Sstevel@tonic-gate * and 4 byte align which is normal for XDR.
23182695d4f4SMarcel Telka * If kRPC (or someone else) does not cooperate, then we
23197c478bd9Sstevel@tonic-gate * just throw away the message.
23207c478bd9Sstevel@tonic-gate */
23212695d4f4SMarcel Telka RPCLOG(1, "mir_wput: kRPC did not leave space for record "
23227c478bd9Sstevel@tonic-gate "fragment header (%d bytes left)\n",
23237c478bd9Sstevel@tonic-gate (int)(rptr - mp->b_datap->db_base));
23247c478bd9Sstevel@tonic-gate freemsg(mp);
23257c478bd9Sstevel@tonic-gate return;
23267c478bd9Sstevel@tonic-gate }
23277c478bd9Sstevel@tonic-gate rptr -= sizeof (uint32_t);
23287c478bd9Sstevel@tonic-gate *(uint32_t *)rptr = htonl(frag_header);
23297c478bd9Sstevel@tonic-gate mp->b_rptr = rptr;
23307c478bd9Sstevel@tonic-gate
23317c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
23327c478bd9Sstevel@tonic-gate if (mir->mir_type == RPC_CLIENT) {
23337c478bd9Sstevel@tonic-gate /*
23347c478bd9Sstevel@tonic-gate * For the client, set mir_clntreq to indicate that the
23357c478bd9Sstevel@tonic-gate * connection is active.
23367c478bd9Sstevel@tonic-gate */
23377c478bd9Sstevel@tonic-gate mir->mir_clntreq = 1;
2338d3d50737SRafael Vanoni mir->mir_use_timestamp = ddi_get_lbolt();
23397c478bd9Sstevel@tonic-gate }
23407c478bd9Sstevel@tonic-gate
23417c478bd9Sstevel@tonic-gate /*
23427c478bd9Sstevel@tonic-gate * If we haven't already queued some data and the downstream module
23437c478bd9Sstevel@tonic-gate * can accept more data, send it on, otherwise we queue the message
23447c478bd9Sstevel@tonic-gate * and take other actions depending on mir_type.
23457c478bd9Sstevel@tonic-gate */
23467c478bd9Sstevel@tonic-gate if (!mir->mir_inwservice && MIR_WCANPUTNEXT(mir, q)) {
23477c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
23487c478bd9Sstevel@tonic-gate
23497c478bd9Sstevel@tonic-gate /*
23507c478bd9Sstevel@tonic-gate * Now we pass the RPC message downstream.
23517c478bd9Sstevel@tonic-gate */
23527c478bd9Sstevel@tonic-gate putnext(q, mp);
23537c478bd9Sstevel@tonic-gate return;
23547c478bd9Sstevel@tonic-gate }
23557c478bd9Sstevel@tonic-gate
23567c478bd9Sstevel@tonic-gate switch (mir->mir_type) {
23577c478bd9Sstevel@tonic-gate case RPC_CLIENT:
23587c478bd9Sstevel@tonic-gate /*
23597c478bd9Sstevel@tonic-gate * Check for a previous duplicate request on the
23607c478bd9Sstevel@tonic-gate * queue. If there is one, then we throw away
23617c478bd9Sstevel@tonic-gate * the current message and let the previous one
23627c478bd9Sstevel@tonic-gate * go through. If we can't find a duplicate, then
23637c478bd9Sstevel@tonic-gate * send this one. This tap dance is an effort
23647c478bd9Sstevel@tonic-gate * to reduce traffic and processing requirements
23657c478bd9Sstevel@tonic-gate * under load conditions.
23667c478bd9Sstevel@tonic-gate */
23677c478bd9Sstevel@tonic-gate if (mir_clnt_dup_request(q, mp)) {
23687c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
23697c478bd9Sstevel@tonic-gate freemsg(mp);
23707c478bd9Sstevel@tonic-gate return;
23717c478bd9Sstevel@tonic-gate }
23727c478bd9Sstevel@tonic-gate break;
23737c478bd9Sstevel@tonic-gate case RPC_SERVER:
23747c478bd9Sstevel@tonic-gate /*
23757c478bd9Sstevel@tonic-gate * Set mir_hold_inbound so that new inbound RPC
23767c478bd9Sstevel@tonic-gate * messages will be held until the client catches
23777c478bd9Sstevel@tonic-gate * up on the earlier replies. This flag is cleared
23787c478bd9Sstevel@tonic-gate * in mir_wsrv after flow control is relieved;
23797c478bd9Sstevel@tonic-gate * the read-side queue is also enabled at that time.
23807c478bd9Sstevel@tonic-gate */
23817c478bd9Sstevel@tonic-gate mir->mir_hold_inbound = 1;
23827c478bd9Sstevel@tonic-gate break;
23837c478bd9Sstevel@tonic-gate default:
23847c478bd9Sstevel@tonic-gate RPCLOG(1, "mir_wput: unexpected mir_type %d\n", mir->mir_type);
23857c478bd9Sstevel@tonic-gate break;
23867c478bd9Sstevel@tonic-gate }
23877c478bd9Sstevel@tonic-gate mir->mir_inwservice = 1;
23887c478bd9Sstevel@tonic-gate (void) putq(q, mp);
23897c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
23907c478bd9Sstevel@tonic-gate }
23917c478bd9Sstevel@tonic-gate
23927c478bd9Sstevel@tonic-gate static void
mir_wput_other(queue_t * q,mblk_t * mp)23937c478bd9Sstevel@tonic-gate mir_wput_other(queue_t *q, mblk_t *mp)
23947c478bd9Sstevel@tonic-gate {
23957c478bd9Sstevel@tonic-gate mir_t *mir = (mir_t *)q->q_ptr;
23967c478bd9Sstevel@tonic-gate struct iocblk *iocp;
23977c478bd9Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr;
23987c478bd9Sstevel@tonic-gate bool_t flush_in_svc = FALSE;
23997c478bd9Sstevel@tonic-gate
24007c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&mir->mir_mutex));
24017c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) {
24027c478bd9Sstevel@tonic-gate case M_IOCTL:
24037c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)rptr;
24047c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) {
24057c478bd9Sstevel@tonic-gate case RPC_CLIENT:
24067c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
24077c478bd9Sstevel@tonic-gate if (mir->mir_type != 0 &&
24087c478bd9Sstevel@tonic-gate mir->mir_type != iocp->ioc_cmd) {
24097c478bd9Sstevel@tonic-gate ioc_eperm:
24107c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
24117c478bd9Sstevel@tonic-gate iocp->ioc_error = EPERM;
24127c478bd9Sstevel@tonic-gate iocp->ioc_count = 0;
24137c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK;
24147c478bd9Sstevel@tonic-gate qreply(q, mp);
24157c478bd9Sstevel@tonic-gate return;
24167c478bd9Sstevel@tonic-gate }
24177c478bd9Sstevel@tonic-gate
24187c478bd9Sstevel@tonic-gate mir->mir_type = iocp->ioc_cmd;
24197c478bd9Sstevel@tonic-gate
24207c478bd9Sstevel@tonic-gate /*
24217c478bd9Sstevel@tonic-gate * Clear mir_hold_inbound which was set to 1 by
24227c478bd9Sstevel@tonic-gate * mir_open. This flag is not used on client
24237c478bd9Sstevel@tonic-gate * streams.
24247c478bd9Sstevel@tonic-gate */
24257c478bd9Sstevel@tonic-gate mir->mir_hold_inbound = 0;
24267c478bd9Sstevel@tonic-gate mir->mir_max_msg_sizep = &clnt_max_msg_size;
24277c478bd9Sstevel@tonic-gate
24287c478bd9Sstevel@tonic-gate /*
24297c478bd9Sstevel@tonic-gate * Start the idle timer. See mir_timer() for more
24307c478bd9Sstevel@tonic-gate * information on how client timers work.
24317c478bd9Sstevel@tonic-gate */
24327c478bd9Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout;
24337c478bd9Sstevel@tonic-gate mir_clnt_idle_start(q, mir);
24347c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
24357c478bd9Sstevel@tonic-gate
24367c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK;
24377c478bd9Sstevel@tonic-gate qreply(q, mp);
24387c478bd9Sstevel@tonic-gate return;
24397c478bd9Sstevel@tonic-gate case RPC_SERVER:
24407c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
24417c478bd9Sstevel@tonic-gate if (mir->mir_type != 0 &&
24427c478bd9Sstevel@tonic-gate mir->mir_type != iocp->ioc_cmd)
24437c478bd9Sstevel@tonic-gate goto ioc_eperm;
24447c478bd9Sstevel@tonic-gate
24457c478bd9Sstevel@tonic-gate /*
24467c478bd9Sstevel@tonic-gate * We don't clear mir_hold_inbound here because
24477c478bd9Sstevel@tonic-gate * mir_hold_inbound is used in the flow control
24487c478bd9Sstevel@tonic-gate * model. If we cleared it here, then we'd commit
24497c478bd9Sstevel@tonic-gate * a small violation to the model where the transport
24507c478bd9Sstevel@tonic-gate * might immediately block downstream flow.
24517c478bd9Sstevel@tonic-gate */
24527c478bd9Sstevel@tonic-gate
24537c478bd9Sstevel@tonic-gate mir->mir_type = iocp->ioc_cmd;
24547c478bd9Sstevel@tonic-gate mir->mir_max_msg_sizep = &svc_max_msg_size;
24557c478bd9Sstevel@tonic-gate
24567c478bd9Sstevel@tonic-gate /*
24577c478bd9Sstevel@tonic-gate * Start the idle timer. See mir_timer() for more
24587c478bd9Sstevel@tonic-gate * information on how server timers work.
24597c478bd9Sstevel@tonic-gate *
24607c478bd9Sstevel@tonic-gate * Note that it is important to start the idle timer
24617c478bd9Sstevel@tonic-gate * here so that connections time out even if we
24627c478bd9Sstevel@tonic-gate * never receive any data on them.
24637c478bd9Sstevel@tonic-gate */
24647c478bd9Sstevel@tonic-gate mir->mir_idle_timeout = svc_idle_timeout;
24657c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wput_other starting idle timer on 0x%p "
24667c478bd9Sstevel@tonic-gate "because we got RPC_SERVER ioctl\n", (void *)q);
24677c478bd9Sstevel@tonic-gate mir_svc_idle_start(q, mir);
24687c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
24697c478bd9Sstevel@tonic-gate
24707c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK;
24717c478bd9Sstevel@tonic-gate qreply(q, mp);
24727c478bd9Sstevel@tonic-gate return;
24737c478bd9Sstevel@tonic-gate default:
24747c478bd9Sstevel@tonic-gate break;
24757c478bd9Sstevel@tonic-gate }
24767c478bd9Sstevel@tonic-gate break;
24777c478bd9Sstevel@tonic-gate
24787c478bd9Sstevel@tonic-gate case M_PROTO:
24797c478bd9Sstevel@tonic-gate if (mir->mir_type == RPC_CLIENT) {
24807c478bd9Sstevel@tonic-gate /*
24817c478bd9Sstevel@tonic-gate * We are likely being called from the context of a
24827c478bd9Sstevel@tonic-gate * service procedure. So we need to enqueue. However
24837c478bd9Sstevel@tonic-gate * enqueing may put our message behind data messages.
24847c478bd9Sstevel@tonic-gate * So flush the data first.
24857c478bd9Sstevel@tonic-gate */
24867c478bd9Sstevel@tonic-gate flush_in_svc = TRUE;
24877c478bd9Sstevel@tonic-gate }
24887c478bd9Sstevel@tonic-gate if ((mp->b_wptr - rptr) < sizeof (uint32_t) ||
24897c478bd9Sstevel@tonic-gate !IS_P2ALIGNED(rptr, sizeof (uint32_t)))
24907c478bd9Sstevel@tonic-gate break;
24917c478bd9Sstevel@tonic-gate
24927c478bd9Sstevel@tonic-gate switch (((union T_primitives *)rptr)->type) {
24937c478bd9Sstevel@tonic-gate case T_DATA_REQ:
24947c478bd9Sstevel@tonic-gate /* Don't pass T_DATA_REQ messages downstream. */
24957c478bd9Sstevel@tonic-gate freemsg(mp);
24967c478bd9Sstevel@tonic-gate return;
24977c478bd9Sstevel@tonic-gate case T_ORDREL_REQ:
24987c478bd9Sstevel@tonic-gate RPCLOG(8, "mir_wput_other wq 0x%p: got T_ORDREL_REQ\n",
24997c478bd9Sstevel@tonic-gate (void *)q);
25007c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
25017c478bd9Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER) {
25027c478bd9Sstevel@tonic-gate /*
25037c478bd9Sstevel@tonic-gate * We are likely being called from
25047c478bd9Sstevel@tonic-gate * clnt_dispatch_notifyall(). Sending
25057c478bd9Sstevel@tonic-gate * a T_ORDREL_REQ will result in
25067c478bd9Sstevel@tonic-gate * a some kind of _IND message being sent,
25077c478bd9Sstevel@tonic-gate * will be another call to
25087c478bd9Sstevel@tonic-gate * clnt_dispatch_notifyall(). To keep the stack
25097c478bd9Sstevel@tonic-gate * lean, queue this message.
25107c478bd9Sstevel@tonic-gate */
25117c478bd9Sstevel@tonic-gate mir->mir_inwservice = 1;
25127c478bd9Sstevel@tonic-gate (void) putq(q, mp);
25137c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
25147c478bd9Sstevel@tonic-gate return;
25157c478bd9Sstevel@tonic-gate }
25167c478bd9Sstevel@tonic-gate
25177c478bd9Sstevel@tonic-gate /*
25187c478bd9Sstevel@tonic-gate * Mark the structure such that we don't accept any
25197c478bd9Sstevel@tonic-gate * more requests from client. We could defer this
25207c478bd9Sstevel@tonic-gate * until we actually send the orderly release
25217c478bd9Sstevel@tonic-gate * request downstream, but all that does is delay
25227c478bd9Sstevel@tonic-gate * the closing of this stream.
25237c478bd9Sstevel@tonic-gate */
25247c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wput_other wq 0x%p: got T_ORDREL_REQ "
25257c478bd9Sstevel@tonic-gate " so calling mir_svc_start_close\n", (void *)q);
25267c478bd9Sstevel@tonic-gate
25277c478bd9Sstevel@tonic-gate mir_svc_start_close(q, mir);
25287c478bd9Sstevel@tonic-gate
25297c478bd9Sstevel@tonic-gate /*
25307c478bd9Sstevel@tonic-gate * If we have sent down a T_ORDREL_REQ, don't send
25317c478bd9Sstevel@tonic-gate * any more.
25327c478bd9Sstevel@tonic-gate */
25337c478bd9Sstevel@tonic-gate if (mir->mir_ordrel_pending) {
25347c478bd9Sstevel@tonic-gate freemsg(mp);
25357c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
25367c478bd9Sstevel@tonic-gate return;
25377c478bd9Sstevel@tonic-gate }
25387c478bd9Sstevel@tonic-gate
25397c478bd9Sstevel@tonic-gate /*
25407c478bd9Sstevel@tonic-gate * If the stream is not idle, then we hold the
25417c478bd9Sstevel@tonic-gate * orderly release until it becomes idle. This
25422695d4f4SMarcel Telka * ensures that kRPC will be able to reply to
25437c478bd9Sstevel@tonic-gate * all requests that we have passed to it.
25447c478bd9Sstevel@tonic-gate *
25457c478bd9Sstevel@tonic-gate * We also queue the request if there is data already
25467c478bd9Sstevel@tonic-gate * queued, because we cannot allow the T_ORDREL_REQ
25477c478bd9Sstevel@tonic-gate * to go before data. When we had a separate reply
25487c478bd9Sstevel@tonic-gate * count, this was not a problem, because the
25497c478bd9Sstevel@tonic-gate * reply count was reconciled when mir_wsrv()
25507c478bd9Sstevel@tonic-gate * completed.
25517c478bd9Sstevel@tonic-gate */
25527c478bd9Sstevel@tonic-gate if (!MIR_SVC_QUIESCED(mir) ||
25537c478bd9Sstevel@tonic-gate mir->mir_inwservice == 1) {
25547c478bd9Sstevel@tonic-gate mir->mir_inwservice = 1;
25557c478bd9Sstevel@tonic-gate (void) putq(q, mp);
25567c478bd9Sstevel@tonic-gate
25577c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wput_other: queuing "
25587c478bd9Sstevel@tonic-gate "T_ORDREL_REQ on 0x%p\n", (void *)q);
25597c478bd9Sstevel@tonic-gate
25607c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
25617c478bd9Sstevel@tonic-gate return;
25627c478bd9Sstevel@tonic-gate }
25637c478bd9Sstevel@tonic-gate
25647c478bd9Sstevel@tonic-gate /*
25657c478bd9Sstevel@tonic-gate * Mark the structure so that we know we sent
25667c478bd9Sstevel@tonic-gate * an orderly release request, and reset the idle timer.
25677c478bd9Sstevel@tonic-gate */
25687c478bd9Sstevel@tonic-gate mir->mir_ordrel_pending = 1;
25697c478bd9Sstevel@tonic-gate
25707c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wput_other: calling mir_svc_idle_start"
25717c478bd9Sstevel@tonic-gate " on 0x%p because we got T_ORDREL_REQ\n",
25727c478bd9Sstevel@tonic-gate (void *)q);
25737c478bd9Sstevel@tonic-gate
25747c478bd9Sstevel@tonic-gate mir_svc_idle_start(q, mir);
25757c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
25767c478bd9Sstevel@tonic-gate
25777c478bd9Sstevel@tonic-gate /*
25787c478bd9Sstevel@tonic-gate * When we break, we will putnext the T_ORDREL_REQ.
25797c478bd9Sstevel@tonic-gate */
25807c478bd9Sstevel@tonic-gate break;
25817c478bd9Sstevel@tonic-gate
25827c478bd9Sstevel@tonic-gate case T_CONN_REQ:
25837c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
25847c478bd9Sstevel@tonic-gate if (mir->mir_head_mp != NULL) {
25857c478bd9Sstevel@tonic-gate freemsg(mir->mir_head_mp);
25867c478bd9Sstevel@tonic-gate mir->mir_head_mp = NULL;
25877c478bd9Sstevel@tonic-gate mir->mir_tail_mp = NULL;
25887c478bd9Sstevel@tonic-gate }
25897c478bd9Sstevel@tonic-gate mir->mir_frag_len = -(int32_t)sizeof (uint32_t);
25907c478bd9Sstevel@tonic-gate /*
25917c478bd9Sstevel@tonic-gate * Restart timer in case mir_clnt_idle_do_stop() was
25927c478bd9Sstevel@tonic-gate * called.
25937c478bd9Sstevel@tonic-gate */
25947c478bd9Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout;
25957c478bd9Sstevel@tonic-gate mir_clnt_idle_stop(q, mir);
25967c478bd9Sstevel@tonic-gate mir_clnt_idle_start(q, mir);
25977c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
25987c478bd9Sstevel@tonic-gate break;
25997c478bd9Sstevel@tonic-gate
26007c478bd9Sstevel@tonic-gate default:
26017c478bd9Sstevel@tonic-gate /*
26027c478bd9Sstevel@tonic-gate * T_DISCON_REQ is one of the interesting default
26037c478bd9Sstevel@tonic-gate * cases here. Ideally, an M_FLUSH is done before
26047c478bd9Sstevel@tonic-gate * T_DISCON_REQ is done. However, that is somewhat
26057c478bd9Sstevel@tonic-gate * cumbersome for clnt_cots.c to do. So we queue
26067c478bd9Sstevel@tonic-gate * T_DISCON_REQ, and let the service procedure
26077c478bd9Sstevel@tonic-gate * flush all M_DATA.
26087c478bd9Sstevel@tonic-gate */
26097c478bd9Sstevel@tonic-gate break;
26107c478bd9Sstevel@tonic-gate }
26117c478bd9Sstevel@tonic-gate /* fallthru */;
26127c478bd9Sstevel@tonic-gate default:
26137c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type >= QPCTL) {
26147c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_FLUSH) {
26157c478bd9Sstevel@tonic-gate if (mir->mir_type == RPC_CLIENT &&
26167c478bd9Sstevel@tonic-gate *mp->b_rptr & FLUSHW) {
26177c478bd9Sstevel@tonic-gate RPCLOG(32, "mir_wput_other: flushing "
26187c478bd9Sstevel@tonic-gate "wq 0x%p\n", (void *)q);
26197c478bd9Sstevel@tonic-gate if (*mp->b_rptr & FLUSHBAND) {
26207c478bd9Sstevel@tonic-gate flushband(q, *(mp->b_rptr + 1),
26217c478bd9Sstevel@tonic-gate FLUSHDATA);
26227c478bd9Sstevel@tonic-gate } else {
26237c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA);
26247c478bd9Sstevel@tonic-gate }
26257c478bd9Sstevel@tonic-gate } else {
26267c478bd9Sstevel@tonic-gate RPCLOG(32, "mir_wput_other: ignoring "
26277c478bd9Sstevel@tonic-gate "M_FLUSH on wq 0x%p\n", (void *)q);
26287c478bd9Sstevel@tonic-gate }
26297c478bd9Sstevel@tonic-gate }
26307c478bd9Sstevel@tonic-gate break;
26317c478bd9Sstevel@tonic-gate }
26327c478bd9Sstevel@tonic-gate
26337c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
26347c478bd9Sstevel@tonic-gate if (mir->mir_inwservice == 0 && MIR_WCANPUTNEXT(mir, q)) {
26357c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
26367c478bd9Sstevel@tonic-gate break;
26377c478bd9Sstevel@tonic-gate }
26387c478bd9Sstevel@tonic-gate mir->mir_inwservice = 1;
26397c478bd9Sstevel@tonic-gate mir->mir_inwflushdata = flush_in_svc;
26407c478bd9Sstevel@tonic-gate (void) putq(q, mp);
26417c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
26427c478bd9Sstevel@tonic-gate qenable(q);
26437c478bd9Sstevel@tonic-gate
26447c478bd9Sstevel@tonic-gate return;
26457c478bd9Sstevel@tonic-gate }
26467c478bd9Sstevel@tonic-gate putnext(q, mp);
26477c478bd9Sstevel@tonic-gate }
26487c478bd9Sstevel@tonic-gate
26497c478bd9Sstevel@tonic-gate static void
mir_wsrv(queue_t * q)26507c478bd9Sstevel@tonic-gate mir_wsrv(queue_t *q)
26517c478bd9Sstevel@tonic-gate {
26527c478bd9Sstevel@tonic-gate mblk_t *mp;
26537c478bd9Sstevel@tonic-gate mir_t *mir;
26547c478bd9Sstevel@tonic-gate bool_t flushdata;
26557c478bd9Sstevel@tonic-gate
26567c478bd9Sstevel@tonic-gate mir = (mir_t *)q->q_ptr;
26577c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
26587c478bd9Sstevel@tonic-gate
26597c478bd9Sstevel@tonic-gate flushdata = mir->mir_inwflushdata;
26607c478bd9Sstevel@tonic-gate mir->mir_inwflushdata = 0;
26617c478bd9Sstevel@tonic-gate
26627c478bd9Sstevel@tonic-gate while (mp = getq(q)) {
26637c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type == M_DATA) {
26647c478bd9Sstevel@tonic-gate /*
26657c478bd9Sstevel@tonic-gate * Do not send any more data if we have sent
26667c478bd9Sstevel@tonic-gate * a T_ORDREL_REQ.
26677c478bd9Sstevel@tonic-gate */
26687c478bd9Sstevel@tonic-gate if (flushdata || mir->mir_ordrel_pending == 1) {
26697c478bd9Sstevel@tonic-gate freemsg(mp);
26707c478bd9Sstevel@tonic-gate continue;
26717c478bd9Sstevel@tonic-gate }
26727c478bd9Sstevel@tonic-gate
26737c478bd9Sstevel@tonic-gate /*
26747c478bd9Sstevel@tonic-gate * Make sure that the stream can really handle more
26757c478bd9Sstevel@tonic-gate * data.
26767c478bd9Sstevel@tonic-gate */
26777c478bd9Sstevel@tonic-gate if (!MIR_WCANPUTNEXT(mir, q)) {
26787c478bd9Sstevel@tonic-gate (void) putbq(q, mp);
26797c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
26807c478bd9Sstevel@tonic-gate return;
26817c478bd9Sstevel@tonic-gate }
26827c478bd9Sstevel@tonic-gate
26837c478bd9Sstevel@tonic-gate /*
26847c478bd9Sstevel@tonic-gate * Now we pass the RPC message downstream.
26857c478bd9Sstevel@tonic-gate */
26867c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
26877c478bd9Sstevel@tonic-gate putnext(q, mp);
26887c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
26897c478bd9Sstevel@tonic-gate continue;
26907c478bd9Sstevel@tonic-gate }
26917c478bd9Sstevel@tonic-gate
26927c478bd9Sstevel@tonic-gate /*
26937c478bd9Sstevel@tonic-gate * This is not an RPC message, pass it downstream
26947c478bd9Sstevel@tonic-gate * (ignoring flow control) if the server side is not sending a
26957c478bd9Sstevel@tonic-gate * T_ORDREL_REQ downstream.
26967c478bd9Sstevel@tonic-gate */
26977c478bd9Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER ||
26987c478bd9Sstevel@tonic-gate ((union T_primitives *)mp->b_rptr)->type !=
26997c478bd9Sstevel@tonic-gate T_ORDREL_REQ) {
27007c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
27017c478bd9Sstevel@tonic-gate putnext(q, mp);
27027c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
27037c478bd9Sstevel@tonic-gate continue;
27047c478bd9Sstevel@tonic-gate }
27057c478bd9Sstevel@tonic-gate
27067c478bd9Sstevel@tonic-gate if (mir->mir_ordrel_pending == 1) {
27077c478bd9Sstevel@tonic-gate /*
27087c478bd9Sstevel@tonic-gate * Don't send two T_ORDRELs
27097c478bd9Sstevel@tonic-gate */
27107c478bd9Sstevel@tonic-gate freemsg(mp);
27117c478bd9Sstevel@tonic-gate continue;
27127c478bd9Sstevel@tonic-gate }
27137c478bd9Sstevel@tonic-gate
27147c478bd9Sstevel@tonic-gate /*
27157c478bd9Sstevel@tonic-gate * Mark the structure so that we know we sent an orderly
27167c478bd9Sstevel@tonic-gate * release request. We will check to see slot is idle at the
27177c478bd9Sstevel@tonic-gate * end of this routine, and if so, reset the idle timer to
27187c478bd9Sstevel@tonic-gate * handle orderly release timeouts.
27197c478bd9Sstevel@tonic-gate */
27207c478bd9Sstevel@tonic-gate mir->mir_ordrel_pending = 1;
27217c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wsrv: sending ordrel req on q 0x%p\n",
27227c478bd9Sstevel@tonic-gate (void *)q);
27237c478bd9Sstevel@tonic-gate /*
27247c478bd9Sstevel@tonic-gate * Send the orderly release downstream. If there are other
27257c478bd9Sstevel@tonic-gate * pending replies we won't be able to send them. However,
27267c478bd9Sstevel@tonic-gate * the only reason we should send the orderly release is if
27277c478bd9Sstevel@tonic-gate * we were idle, or if an unusual event occurred.
27287c478bd9Sstevel@tonic-gate */
27297c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
27307c478bd9Sstevel@tonic-gate putnext(q, mp);
27317c478bd9Sstevel@tonic-gate mutex_enter(&mir->mir_mutex);
27327c478bd9Sstevel@tonic-gate }
27337c478bd9Sstevel@tonic-gate
27347c478bd9Sstevel@tonic-gate if (q->q_first == NULL)
27357c478bd9Sstevel@tonic-gate /*
27367c478bd9Sstevel@tonic-gate * If we call mir_svc_idle_start() below, then
27377c478bd9Sstevel@tonic-gate * clearing mir_inwservice here will also result in
27387c478bd9Sstevel@tonic-gate * any thread waiting in mir_close() to be signaled.
27397c478bd9Sstevel@tonic-gate */
27407c478bd9Sstevel@tonic-gate mir->mir_inwservice = 0;
27417c478bd9Sstevel@tonic-gate
27427c478bd9Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER) {
27437c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
27447c478bd9Sstevel@tonic-gate return;
27457c478bd9Sstevel@tonic-gate }
27467c478bd9Sstevel@tonic-gate
27477c478bd9Sstevel@tonic-gate /*
27487c478bd9Sstevel@tonic-gate * If idle we call mir_svc_idle_start to start the timer (or wakeup
27497c478bd9Sstevel@tonic-gate * a close). Also make sure not to start the idle timer on the
27507c478bd9Sstevel@tonic-gate * listener stream. This can cause nfsd to send an orderly release
27517c478bd9Sstevel@tonic-gate * command on the listener stream.
27527c478bd9Sstevel@tonic-gate */
27537c478bd9Sstevel@tonic-gate if (MIR_SVC_QUIESCED(mir) && !(mir->mir_listen_stream)) {
27547c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_wsrv: calling mir_svc_idle_start on 0x%p "
27557c478bd9Sstevel@tonic-gate "because mir slot is idle\n", (void *)q);
27567c478bd9Sstevel@tonic-gate mir_svc_idle_start(q, mir);
27577c478bd9Sstevel@tonic-gate }
27587c478bd9Sstevel@tonic-gate
27597c478bd9Sstevel@tonic-gate /*
27607c478bd9Sstevel@tonic-gate * If outbound flow control has been relieved, then allow new
27617c478bd9Sstevel@tonic-gate * inbound requests to be processed.
27627c478bd9Sstevel@tonic-gate */
27637c478bd9Sstevel@tonic-gate if (mir->mir_hold_inbound) {
27647c478bd9Sstevel@tonic-gate mir->mir_hold_inbound = 0;
27657c478bd9Sstevel@tonic-gate qenable(RD(q));
27667c478bd9Sstevel@tonic-gate }
27677c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
27687c478bd9Sstevel@tonic-gate }
27697c478bd9Sstevel@tonic-gate
27707c478bd9Sstevel@tonic-gate static void
mir_disconnect(queue_t * q,mir_t * mir)27717c478bd9Sstevel@tonic-gate mir_disconnect(queue_t *q, mir_t *mir)
27727c478bd9Sstevel@tonic-gate {
27737c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&mir->mir_mutex));
27747c478bd9Sstevel@tonic-gate
27757c478bd9Sstevel@tonic-gate switch (mir->mir_type) {
27767c478bd9Sstevel@tonic-gate case RPC_CLIENT:
27777c478bd9Sstevel@tonic-gate /*
27787c478bd9Sstevel@tonic-gate * We are disconnecting, but not necessarily
27797c478bd9Sstevel@tonic-gate * closing. By not closing, we will fail to
27807c478bd9Sstevel@tonic-gate * pick up a possibly changed global timeout value,
27817c478bd9Sstevel@tonic-gate * unless we store it now.
27827c478bd9Sstevel@tonic-gate */
27837c478bd9Sstevel@tonic-gate mir->mir_idle_timeout = clnt_idle_timeout;
27847c478bd9Sstevel@tonic-gate mir_clnt_idle_start(WR(q), mir);
27857c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
27867c478bd9Sstevel@tonic-gate
27877c478bd9Sstevel@tonic-gate /*
27882695d4f4SMarcel Telka * T_DISCON_REQ is passed to kRPC as an integer value
27897c478bd9Sstevel@tonic-gate * (this is not a TPI message). It is used as a
27907c478bd9Sstevel@tonic-gate * convenient value to indicate a sanity check
27912695d4f4SMarcel Telka * failure -- the same kRPC routine is also called
27927c478bd9Sstevel@tonic-gate * for T_DISCON_INDs and T_ORDREL_INDs.
27937c478bd9Sstevel@tonic-gate */
27947c478bd9Sstevel@tonic-gate clnt_dispatch_notifyall(WR(q), T_DISCON_REQ, 0);
27957c478bd9Sstevel@tonic-gate break;
27967c478bd9Sstevel@tonic-gate
27977c478bd9Sstevel@tonic-gate case RPC_SERVER:
27987c478bd9Sstevel@tonic-gate mir->mir_svc_no_more_msgs = 1;
27997c478bd9Sstevel@tonic-gate mir_svc_idle_stop(WR(q), mir);
28007c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
28017c478bd9Sstevel@tonic-gate RPCLOG(16, "mir_disconnect: telling "
28027c478bd9Sstevel@tonic-gate "stream head listener to disconnect stream "
28037c478bd9Sstevel@tonic-gate "(0x%p)\n", (void *) q);
28047c478bd9Sstevel@tonic-gate (void) mir_svc_policy_notify(q, 2);
28057c478bd9Sstevel@tonic-gate break;
28067c478bd9Sstevel@tonic-gate
28077c478bd9Sstevel@tonic-gate default:
28087c478bd9Sstevel@tonic-gate mutex_exit(&mir->mir_mutex);
28097c478bd9Sstevel@tonic-gate break;
28107c478bd9Sstevel@tonic-gate }
28117c478bd9Sstevel@tonic-gate }
28127c478bd9Sstevel@tonic-gate
28137c478bd9Sstevel@tonic-gate /*
2814153adbb6Smeem * Sanity check the message length, and if it's too large, shutdown the
2815153adbb6Smeem * connection. Returns 1 if the connection is shutdown; 0 otherwise.
28167c478bd9Sstevel@tonic-gate */
28177c478bd9Sstevel@tonic-gate static int
mir_check_len(queue_t * q,mblk_t * head_mp)2818*3b3b7026SMarcel Telka mir_check_len(queue_t *q, mblk_t *head_mp)
28197c478bd9Sstevel@tonic-gate {
2820153adbb6Smeem mir_t *mir = q->q_ptr;
2821153adbb6Smeem uint_t maxsize = 0;
2822*3b3b7026SMarcel Telka size_t msg_len = msgdsize(head_mp);
28237c478bd9Sstevel@tonic-gate
2824153adbb6Smeem if (mir->mir_max_msg_sizep != NULL)
2825153adbb6Smeem maxsize = *mir->mir_max_msg_sizep;
28267c478bd9Sstevel@tonic-gate
2827*3b3b7026SMarcel Telka if (maxsize == 0 || msg_len <= maxsize)
28287c478bd9Sstevel@tonic-gate return (0);
28297c478bd9Sstevel@tonic-gate
28307c478bd9Sstevel@tonic-gate freemsg(head_mp);
2831153adbb6Smeem mir->mir_head_mp = NULL;
2832153adbb6Smeem mir->mir_tail_mp = NULL;
2833153adbb6Smeem mir->mir_frag_header = 0;
2834153adbb6Smeem mir->mir_frag_len = -(int32_t)sizeof (uint32_t);
28357c478bd9Sstevel@tonic-gate if (mir->mir_type != RPC_SERVER || mir->mir_setup_complete) {
28367c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE,
2837*3b3b7026SMarcel Telka "kRPC: record fragment from %s of size(%lu) exceeds "
28387c478bd9Sstevel@tonic-gate "maximum (%u). Disconnecting",
28397c478bd9Sstevel@tonic-gate (mir->mir_type == RPC_CLIENT) ? "server" :
28407c478bd9Sstevel@tonic-gate (mir->mir_type == RPC_SERVER) ? "client" :
2841*3b3b7026SMarcel Telka "test tool", msg_len, maxsize);
28427c478bd9Sstevel@tonic-gate }
28437c478bd9Sstevel@tonic-gate
28447c478bd9Sstevel@tonic-gate mir_disconnect(q, mir);
28457c478bd9Sstevel@tonic-gate return (1);
28467c478bd9Sstevel@tonic-gate }
2847