xref: /onnv-gate/usr/src/cmd/lvm/rpc.mdcommd/mdmn_subr.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <unistd.h>
30*0Sstevel@tonic-gate #include <sys/types.h>
31*0Sstevel@tonic-gate #include <sys/socket.h>
32*0Sstevel@tonic-gate #include <netinet/in.h>
33*0Sstevel@tonic-gate #include <arpa/inet.h>
34*0Sstevel@tonic-gate #include <thread.h>
35*0Sstevel@tonic-gate #include "meta.h"
36*0Sstevel@tonic-gate #include "mdmn_subr.h"
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate extern int mdmn_init_set(set_t setno, int todo);
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate uint_t mdmn_busy[MD_MAXSETS][MD_MN_NCLASSES];
41*0Sstevel@tonic-gate mutex_t	mdmn_busy_mutex[MD_MAXSETS];
42*0Sstevel@tonic-gate cond_t	mdmn_busy_cv[MD_MAXSETS];
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate /* the wakeup table for the initiator's side */
46*0Sstevel@tonic-gate mdmn_wti_t mdmn_initiator_table[MD_MAXSETS][MD_MN_NCLASSES];
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate /* the wakeup table for the master */
49*0Sstevel@tonic-gate mdmn_wtm_t mdmn_master_table[MD_MAXSETS][MD_MN_NCLASSES];
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate /* List of licensed ip addresses */
52*0Sstevel@tonic-gate licensed_ip_t   licensed_nodes[NNODES];
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate /* speed up the search for licensed ip addresses */
55*0Sstevel@tonic-gate md_mn_nodeid_t maxlicnodes = 0; /* 0 is not a valid node ID */
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate /*
58*0Sstevel@tonic-gate  * Check if a given set/class combination is currently in use
59*0Sstevel@tonic-gate  * If in use, returns TRUE
60*0Sstevel@tonic-gate  * Otherwise returns FALSE
61*0Sstevel@tonic-gate  *
62*0Sstevel@tonic-gate  * Must be called with mdmn_busy_mutex held
63*0Sstevel@tonic-gate  */
64*0Sstevel@tonic-gate bool_t
65*0Sstevel@tonic-gate mdmn_is_class_busy(set_t setno, md_mn_msgclass_t class)
66*0Sstevel@tonic-gate {
67*0Sstevel@tonic-gate 	if (mdmn_busy[setno][class] & MDMN_BUSY) {
68*0Sstevel@tonic-gate 		return (TRUE);
69*0Sstevel@tonic-gate 	} else {
70*0Sstevel@tonic-gate 		return (FALSE);
71*0Sstevel@tonic-gate 	}
72*0Sstevel@tonic-gate }
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate /*
75*0Sstevel@tonic-gate  * Mark a given set/class combination as currently in use
76*0Sstevel@tonic-gate  * If the class was already in use, returns FALSE
77*0Sstevel@tonic-gate  * Otherwise returns TRUE
78*0Sstevel@tonic-gate  *
79*0Sstevel@tonic-gate  * So mdmn_mark_class_busy can be used like
80*0Sstevel@tonic-gate  * if (mdmn_mark_class_busy(setno, class) == FALSE)
81*0Sstevel@tonic-gate  * 	failure;
82*0Sstevel@tonic-gate  * else
83*0Sstevel@tonic-gate  *	success;
84*0Sstevel@tonic-gate  *
85*0Sstevel@tonic-gate  * Must be called with mdmn_busy_mutex held
86*0Sstevel@tonic-gate  */
87*0Sstevel@tonic-gate bool_t
88*0Sstevel@tonic-gate mdmn_mark_class_busy(set_t setno, md_mn_msgclass_t class)
89*0Sstevel@tonic-gate {
90*0Sstevel@tonic-gate 	if (mdmn_busy[setno][class] & MDMN_BUSY) {
91*0Sstevel@tonic-gate 		return (FALSE);
92*0Sstevel@tonic-gate 	} else {
93*0Sstevel@tonic-gate 		mdmn_busy[setno][class] |= MDMN_BUSY;
94*0Sstevel@tonic-gate 		commd_debug(MD_MMV_MISC, "busy: set=%d, class=%d\n",
95*0Sstevel@tonic-gate 		    setno, class);
96*0Sstevel@tonic-gate 		return (TRUE);
97*0Sstevel@tonic-gate 	}
98*0Sstevel@tonic-gate }
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate /*
101*0Sstevel@tonic-gate  * Mark a given set/class combination as currently available
102*0Sstevel@tonic-gate  * Always succeeds, thus void.
103*0Sstevel@tonic-gate  *
104*0Sstevel@tonic-gate  * If this class is marked MDMN_SUSPEND_ALL, we are in the middle of
105*0Sstevel@tonic-gate  * draining all classes of this set.
106*0Sstevel@tonic-gate  * We have to mark class+1 as MDMN_SUSPEND_ALL too.
107*0Sstevel@tonic-gate  * If class+2 wasn't busy, we proceed with class+2, and so on
108*0Sstevel@tonic-gate  * If any class is busy, we return.
109*0Sstevel@tonic-gate  * Then the drain process will be continued by the mdmn_mark_class_unbusy() of
110*0Sstevel@tonic-gate  * that busy class
111*0Sstevel@tonic-gate  */
112*0Sstevel@tonic-gate void
113*0Sstevel@tonic-gate mdmn_mark_class_unbusy(set_t setno, md_mn_msgclass_t class)
114*0Sstevel@tonic-gate {
115*0Sstevel@tonic-gate 	commd_debug(MD_MMV_MISC, "unbusy: set=%d, class=%d\n", setno, class);
116*0Sstevel@tonic-gate 	mdmn_busy[setno][class] &= ~MDMN_BUSY;
117*0Sstevel@tonic-gate 	/* something changed, inform threads waiting for that */
118*0Sstevel@tonic-gate 	cond_signal(&mdmn_busy_cv[setno]);
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	if ((mdmn_busy[setno][class] & MDMN_SUSPEND_ALL) == 0) {
121*0Sstevel@tonic-gate 		return;
122*0Sstevel@tonic-gate 	}
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	while (++class < MD_MN_NCLASSES) {
125*0Sstevel@tonic-gate 		commd_debug(MD_MMV_MISC,
126*0Sstevel@tonic-gate 		    "unbusy: suspending set=%d, class=%d\n", setno, class);
127*0Sstevel@tonic-gate 		if (mdmn_mark_class_suspended(setno, class, MDMN_SUSPEND_ALL)
128*0Sstevel@tonic-gate 		    == MDMNE_SET_NOT_DRAINED) {
129*0Sstevel@tonic-gate 			break;
130*0Sstevel@tonic-gate 		}
131*0Sstevel@tonic-gate 	}
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate }
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate /*
137*0Sstevel@tonic-gate  * Check if a given set/class combination is locked.
138*0Sstevel@tonic-gate  */
139*0Sstevel@tonic-gate bool_t
140*0Sstevel@tonic-gate mdmn_is_class_locked(set_t setno, md_mn_msgclass_t class)
141*0Sstevel@tonic-gate {
142*0Sstevel@tonic-gate 	if (mdmn_busy[setno][class] & MDMN_LOCKED) {
143*0Sstevel@tonic-gate 		return (TRUE);
144*0Sstevel@tonic-gate 	} else {
145*0Sstevel@tonic-gate 		return (FALSE);
146*0Sstevel@tonic-gate 	}
147*0Sstevel@tonic-gate }
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate /*
150*0Sstevel@tonic-gate  * Mark a given set/class combination as locked.
151*0Sstevel@tonic-gate  * No checking is done here, so routine can be void.
152*0Sstevel@tonic-gate  * Locking a locked set/class is ok.
153*0Sstevel@tonic-gate  *
154*0Sstevel@tonic-gate  * Must be called with mdmn_busy_mutex held
155*0Sstevel@tonic-gate  */
156*0Sstevel@tonic-gate void
157*0Sstevel@tonic-gate mdmn_mark_class_locked(set_t setno, md_mn_msgclass_t class)
158*0Sstevel@tonic-gate {
159*0Sstevel@tonic-gate 	mdmn_busy[setno][class] |= MDMN_LOCKED;
160*0Sstevel@tonic-gate }
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate /*
163*0Sstevel@tonic-gate  * Mark a given set/class combination as unlocked.
164*0Sstevel@tonic-gate  * No checking is done here, so routine can be void.
165*0Sstevel@tonic-gate  * Unlocking a unlocked set/class is ok.
166*0Sstevel@tonic-gate  *
167*0Sstevel@tonic-gate  * Must be called with mdmn_busy_mutex held
168*0Sstevel@tonic-gate  */
169*0Sstevel@tonic-gate void
170*0Sstevel@tonic-gate mdmn_mark_class_unlocked(set_t setno, md_mn_msgclass_t class)
171*0Sstevel@tonic-gate {
172*0Sstevel@tonic-gate 	mdmn_busy[setno][class] &= ~MDMN_LOCKED;
173*0Sstevel@tonic-gate }
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate /*
176*0Sstevel@tonic-gate  * Suspend a set/class combination
177*0Sstevel@tonic-gate  *
178*0Sstevel@tonic-gate  * If called during draining all classes of a set susptype is MDMN_SUSPEND_ALL.
179*0Sstevel@tonic-gate  * If only one class is about to be drained susptype is MDMN_SUSPEND_1.
180*0Sstevel@tonic-gate  *
181*0Sstevel@tonic-gate  * Returns:
182*0Sstevel@tonic-gate  *	MDMNE_ACK if there are no outstanding messages
183*0Sstevel@tonic-gate  *	MDMNE_SET_NOT_DRAINED otherwise
184*0Sstevel@tonic-gate  *
185*0Sstevel@tonic-gate  * Must be called with mdmn_busy_mutex held for this set.
186*0Sstevel@tonic-gate  */
187*0Sstevel@tonic-gate int
188*0Sstevel@tonic-gate mdmn_mark_class_suspended(set_t setno, md_mn_msgclass_t class, uint_t susptype)
189*0Sstevel@tonic-gate {
190*0Sstevel@tonic-gate 	/*
191*0Sstevel@tonic-gate 	 * We use the mdmn_busy array to mark this set is suspended.
192*0Sstevel@tonic-gate 	 */
193*0Sstevel@tonic-gate 	mdmn_busy[setno][class] |= susptype;
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	/*
196*0Sstevel@tonic-gate 	 * If there are outstanding messages for this set/class we
197*0Sstevel@tonic-gate 	 * return MDMNE_SET_NOT_DRAINED, otherwise we return MDMNE_ACK
198*0Sstevel@tonic-gate 	 */
199*0Sstevel@tonic-gate 	if (mdmn_is_class_busy(setno, class) == TRUE) {
200*0Sstevel@tonic-gate 		return (MDMNE_SET_NOT_DRAINED);
201*0Sstevel@tonic-gate 	}
202*0Sstevel@tonic-gate 	return (MDMNE_ACK);
203*0Sstevel@tonic-gate }
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate /*
206*0Sstevel@tonic-gate  * Resume operation for a set/class combination after it was
207*0Sstevel@tonic-gate  * previously suspended
208*0Sstevel@tonic-gate  *
209*0Sstevel@tonic-gate  * If called from mdmn_comm_resume_svc_1 to resume _one_ specific class
210*0Sstevel@tonic-gate  * then susptype will be MDMN_SUSPEND_1
211*0Sstevel@tonic-gate  * Otherwise to resume all classes of one set,
212*0Sstevel@tonic-gate  * then susptype equals (MDMN_SUSPEND_ALL | MDMN_SUSPEND_1)
213*0Sstevel@tonic-gate  *
214*0Sstevel@tonic-gate  * Always succeeds, thus void.
215*0Sstevel@tonic-gate  *
216*0Sstevel@tonic-gate  * Must be called with mdmn_busy_mutex held for this set.
217*0Sstevel@tonic-gate  */
218*0Sstevel@tonic-gate void
219*0Sstevel@tonic-gate mdmn_mark_class_resumed(set_t setno, md_mn_msgclass_t class, uint_t susptype)
220*0Sstevel@tonic-gate {
221*0Sstevel@tonic-gate 	/* simply the reverse operation to mdmn_mark_set_drained() */
222*0Sstevel@tonic-gate 	mdmn_busy[setno][class] &= ~susptype;
223*0Sstevel@tonic-gate }
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate /*
226*0Sstevel@tonic-gate  * Check if a drain command was issued for this set/class combination.
227*0Sstevel@tonic-gate  *
228*0Sstevel@tonic-gate  * Must be called with mdmn_busy_mutex held for this set.
229*0Sstevel@tonic-gate  */
230*0Sstevel@tonic-gate bool_t
231*0Sstevel@tonic-gate mdmn_is_class_suspended(set_t setno, md_mn_msgclass_t class)
232*0Sstevel@tonic-gate {
233*0Sstevel@tonic-gate 	if (mdmn_busy[setno][class] & (MDMN_SUSPEND_ALL | MDMN_SUSPEND_1)) {
234*0Sstevel@tonic-gate 		return (TRUE);
235*0Sstevel@tonic-gate 	} else {
236*0Sstevel@tonic-gate 		return (FALSE);
237*0Sstevel@tonic-gate 	}
238*0Sstevel@tonic-gate }
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate /*
241*0Sstevel@tonic-gate  * Put a result into the wakeup table for the master
242*0Sstevel@tonic-gate  * It's ensured that the msg id from the master_table entry and from
243*0Sstevel@tonic-gate  * result are matching
244*0Sstevel@tonic-gate  */
245*0Sstevel@tonic-gate void
246*0Sstevel@tonic-gate mdmn_set_master_table_res(set_t setno, md_mn_msgclass_t class,
247*0Sstevel@tonic-gate 				md_mn_result_t  *res)
248*0Sstevel@tonic-gate {
249*0Sstevel@tonic-gate 	mdmn_master_table[setno][class].wtm_result = res;
250*0Sstevel@tonic-gate }
251*0Sstevel@tonic-gate void
252*0Sstevel@tonic-gate mdmn_set_master_table_id(set_t setno, md_mn_msgclass_t class, md_mn_msgid_t *id)
253*0Sstevel@tonic-gate {
254*0Sstevel@tonic-gate 	MSGID_COPY(id, &(mdmn_master_table[setno][class].wtm_id));
255*0Sstevel@tonic-gate }
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate void
258*0Sstevel@tonic-gate mdmn_set_master_table_addr(set_t setno, md_mn_msgclass_t class,
259*0Sstevel@tonic-gate     md_mn_nodeid_t nid)
260*0Sstevel@tonic-gate {
261*0Sstevel@tonic-gate 	mdmn_master_table[setno][class].wtm_addr = nid;
262*0Sstevel@tonic-gate }
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate md_mn_result_t *
266*0Sstevel@tonic-gate mdmn_get_master_table_res(set_t setno, md_mn_msgclass_t class)
267*0Sstevel@tonic-gate {
268*0Sstevel@tonic-gate 	return (mdmn_master_table[setno][class].wtm_result);
269*0Sstevel@tonic-gate }
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate void
272*0Sstevel@tonic-gate mdmn_get_master_table_id(set_t setno, md_mn_msgclass_t class, md_mn_msgid_t *id)
273*0Sstevel@tonic-gate {
274*0Sstevel@tonic-gate 	MSGID_COPY(&(mdmn_master_table[setno][class].wtm_id), id);
275*0Sstevel@tonic-gate }
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate cond_t *
278*0Sstevel@tonic-gate mdmn_get_master_table_cv(set_t setno, md_mn_msgclass_t class)
279*0Sstevel@tonic-gate {
280*0Sstevel@tonic-gate 	return (&(mdmn_master_table[setno][class].wtm_cv));
281*0Sstevel@tonic-gate }
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate mutex_t *
284*0Sstevel@tonic-gate mdmn_get_master_table_mx(set_t setno, md_mn_msgclass_t class)
285*0Sstevel@tonic-gate {
286*0Sstevel@tonic-gate 	return (&(mdmn_master_table[setno][class].wtm_mx));
287*0Sstevel@tonic-gate }
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate md_mn_nodeid_t
290*0Sstevel@tonic-gate mdmn_get_master_table_addr(set_t setno, md_mn_msgclass_t class)
291*0Sstevel@tonic-gate {
292*0Sstevel@tonic-gate 	return (mdmn_master_table[setno][class].wtm_addr);
293*0Sstevel@tonic-gate }
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate /* here come the functions dealing with the wakeup table for the initiators */
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate void
301*0Sstevel@tonic-gate mdmn_register_initiator_table(set_t setno, md_mn_msgclass_t class,
302*0Sstevel@tonic-gate     md_mn_msg_t *msg, SVCXPRT *transp)
303*0Sstevel@tonic-gate {
304*0Sstevel@tonic-gate 	uint_t nnodes	= set_descriptor[setno]->sd_mn_numnodes;
305*0Sstevel@tonic-gate 	time_t timeout	= mdmn_get_timeout(msg->msg_type);
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	MSGID_COPY(&(msg->msg_msgid),
309*0Sstevel@tonic-gate 	    &(mdmn_initiator_table[setno][class].wti_id));
310*0Sstevel@tonic-gate 	mdmn_initiator_table[setno][class].wti_transp = transp;
311*0Sstevel@tonic-gate 	mdmn_initiator_table[setno][class].wti_args = (char *)msg;
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	/*
314*0Sstevel@tonic-gate 	 * as the point in time where we want to be guaranteed to be woken up
315*0Sstevel@tonic-gate 	 * again, we chose the
316*0Sstevel@tonic-gate 	 * current time + nnodes times the timeout value for the message type
317*0Sstevel@tonic-gate 	 */
318*0Sstevel@tonic-gate 	mdmn_initiator_table[setno][class].wti_time =
319*0Sstevel@tonic-gate 	    time((time_t *)NULL) + (nnodes * timeout);
320*0Sstevel@tonic-gate }
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate /*
323*0Sstevel@tonic-gate  * If the set/class combination is currently busy, return MDMNE_CLASS_BUSY
324*0Sstevel@tonic-gate  * Otherwise return MDMNE_ACK
325*0Sstevel@tonic-gate  */
326*0Sstevel@tonic-gate int
327*0Sstevel@tonic-gate mdmn_check_initiator_table(set_t setno, md_mn_msgclass_t class)
328*0Sstevel@tonic-gate {
329*0Sstevel@tonic-gate 	if ((mdmn_initiator_table[setno][class].wti_id.mid_nid == ~0u) &&
330*0Sstevel@tonic-gate 	    (mdmn_initiator_table[setno][class].wti_transp == (SVCXPRT *)NULL))
331*0Sstevel@tonic-gate 		return (MDMNE_ACK);
332*0Sstevel@tonic-gate 	return (MDMNE_CLASS_BUSY);
333*0Sstevel@tonic-gate }
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate /*
336*0Sstevel@tonic-gate  * Remove an entry from the initiator table entirely,
337*0Sstevel@tonic-gate  * This must be done with mutex held.
338*0Sstevel@tonic-gate  */
339*0Sstevel@tonic-gate void
340*0Sstevel@tonic-gate mdmn_unregister_initiator_table(set_t setno, md_mn_msgclass_t class)
341*0Sstevel@tonic-gate {
342*0Sstevel@tonic-gate 	mdmn_initiator_table[setno][class].wti_id.mid_nid = ~0u;
343*0Sstevel@tonic-gate 	mdmn_initiator_table[setno][class].wti_id.mid_time = 0LL;
344*0Sstevel@tonic-gate 	mdmn_initiator_table[setno][class].wti_transp = (SVCXPRT *)NULL;
345*0Sstevel@tonic-gate 	mdmn_initiator_table[setno][class].wti_args = (char *)0;
346*0Sstevel@tonic-gate 	mdmn_initiator_table[setno][class].wti_time = (time_t)0;
347*0Sstevel@tonic-gate }
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate void
350*0Sstevel@tonic-gate mdmn_get_initiator_table_id(set_t setno, md_mn_msgclass_t class,
351*0Sstevel@tonic-gate 				md_mn_msgid_t *mid)
352*0Sstevel@tonic-gate {
353*0Sstevel@tonic-gate 	MSGID_COPY(&(mdmn_initiator_table[setno][class].wti_id), mid);
354*0Sstevel@tonic-gate }
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate SVCXPRT *
357*0Sstevel@tonic-gate mdmn_get_initiator_table_transp(set_t setno, md_mn_msgclass_t class)
358*0Sstevel@tonic-gate {
359*0Sstevel@tonic-gate 	return (mdmn_initiator_table[setno][class].wti_transp);
360*0Sstevel@tonic-gate }
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate char *
363*0Sstevel@tonic-gate mdmn_get_initiator_table_args(set_t setno, md_mn_msgclass_t class)
364*0Sstevel@tonic-gate {
365*0Sstevel@tonic-gate 	return (mdmn_initiator_table[setno][class].wti_args);
366*0Sstevel@tonic-gate }
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate mutex_t *
369*0Sstevel@tonic-gate mdmn_get_initiator_table_mx(set_t setno, md_mn_msgclass_t class)
370*0Sstevel@tonic-gate {
371*0Sstevel@tonic-gate 	return (&(mdmn_initiator_table[setno][class].wti_mx));
372*0Sstevel@tonic-gate }
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate time_t
375*0Sstevel@tonic-gate mdmn_get_initiator_table_time(set_t setno, md_mn_msgclass_t class)
376*0Sstevel@tonic-gate {
377*0Sstevel@tonic-gate 	return (mdmn_initiator_table[setno][class].wti_time);
378*0Sstevel@tonic-gate }
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate extern uint_t	md_commd_global_verb;	/* global bitmask for debug classes */
381*0Sstevel@tonic-gate extern FILE	*commdout;		/* debug output file for the commd */
382*0Sstevel@tonic-gate extern hrtime_t __savetime;
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate /*
386*0Sstevel@tonic-gate  * Print debug messages to the terminal or to syslog
387*0Sstevel@tonic-gate  * commd_debug(MD_MMV_SYSLOG,....) is always printed (and always via syslog),
388*0Sstevel@tonic-gate  * even if md_commd_global_verb is zero.
389*0Sstevel@tonic-gate  *
390*0Sstevel@tonic-gate  * Otherwise the correct bit must be set in the bitmask md_commd_global_verb
391*0Sstevel@tonic-gate  */
392*0Sstevel@tonic-gate void
393*0Sstevel@tonic-gate commd_debug(uint_t debug_class, const char *message, ...)
394*0Sstevel@tonic-gate {
395*0Sstevel@tonic-gate 	va_list ap;
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	/* Is this a message for syslog? */
398*0Sstevel@tonic-gate 	if (debug_class == MD_MMV_SYSLOG) {
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 		va_start(ap, message);
401*0Sstevel@tonic-gate 		(void) vsyslog(LOG_WARNING, message, ap);
402*0Sstevel@tonic-gate 		va_end(ap);
403*0Sstevel@tonic-gate 	} else {
404*0Sstevel@tonic-gate 		/* Is this debug_class set in the global verbosity state?  */
405*0Sstevel@tonic-gate 		if ((md_commd_global_verb & debug_class) == 0) {
406*0Sstevel@tonic-gate 			return;
407*0Sstevel@tonic-gate 		}
408*0Sstevel@tonic-gate 		/* Is our output file already functioning? */
409*0Sstevel@tonic-gate 		if (commdout == NULL) {
410*0Sstevel@tonic-gate 			return;
411*0Sstevel@tonic-gate 		}
412*0Sstevel@tonic-gate 		/* Are timestamps activated ? */
413*0Sstevel@tonic-gate 		if (md_commd_global_verb & MD_MMV_TIMESTAMP) {
414*0Sstevel@tonic-gate 			/* print time since last TRESET in usecs */
415*0Sstevel@tonic-gate 			fprintf(commdout, "[%s]",
416*0Sstevel@tonic-gate 			    meta_print_hrtime(gethrtime() - __savetime));
417*0Sstevel@tonic-gate 		}
418*0Sstevel@tonic-gate 		/* Now print the real message */
419*0Sstevel@tonic-gate 		va_start(ap, message);
420*0Sstevel@tonic-gate 		(void) vfprintf(commdout, message, ap);
421*0Sstevel@tonic-gate 		va_end(ap);
422*0Sstevel@tonic-gate 	}
423*0Sstevel@tonic-gate }
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate void
427*0Sstevel@tonic-gate dump_hex(uint_t debug_class, unsigned int *x, int cnt)
428*0Sstevel@tonic-gate {
429*0Sstevel@tonic-gate 	cnt /= sizeof (unsigned int);
430*0Sstevel@tonic-gate 	while (cnt--) {
431*0Sstevel@tonic-gate 		commd_debug(debug_class, "0x%8x ", *x++);
432*0Sstevel@tonic-gate 		if (cnt % 4)
433*0Sstevel@tonic-gate 			continue;
434*0Sstevel@tonic-gate 		commd_debug(debug_class, "\n");
435*0Sstevel@tonic-gate 	}
436*0Sstevel@tonic-gate 	commd_debug(debug_class, "\n");
437*0Sstevel@tonic-gate }
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate /* debug output: dump a message */
440*0Sstevel@tonic-gate void
441*0Sstevel@tonic-gate dump_msg(uint_t dbc, char *prefix, md_mn_msg_t *msg)
442*0Sstevel@tonic-gate {
443*0Sstevel@tonic-gate 	commd_debug(dbc, "%s &msg	= 0x%x\n", prefix, (int)msg);
444*0Sstevel@tonic-gate 	commd_debug(dbc, "%s ID	= (%d, 0x%llx-%d)\n", prefix,
445*0Sstevel@tonic-gate 	    MSGID_ELEMS(msg->msg_msgid));
446*0Sstevel@tonic-gate 	commd_debug(dbc, "%s sender	= %d\n", prefix, msg->msg_sender);
447*0Sstevel@tonic-gate 	commd_debug(dbc, "%s flags	= 0x%x\n", prefix, msg->msg_flags);
448*0Sstevel@tonic-gate 	commd_debug(dbc, "%s setno	= %d\n", prefix, msg->msg_setno);
449*0Sstevel@tonic-gate 	commd_debug(dbc, "%s type	= %d\n", prefix, msg->msg_type);
450*0Sstevel@tonic-gate 	commd_debug(dbc, "%s size	= %d\n", prefix, msg->msg_event_size);
451*0Sstevel@tonic-gate 	if (msg->msg_event_size) {
452*0Sstevel@tonic-gate 		commd_debug(dbc, "%s data	=\n", prefix);
453*0Sstevel@tonic-gate 		dump_hex(dbc, (unsigned int *)(void *)msg->msg_event_data,
454*0Sstevel@tonic-gate 		    msg->msg_event_size);
455*0Sstevel@tonic-gate 	}
456*0Sstevel@tonic-gate }
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate /* debug output: dump a result structure */
459*0Sstevel@tonic-gate void
460*0Sstevel@tonic-gate dump_result(uint_t dbc, char *prefix, md_mn_result_t *res)
461*0Sstevel@tonic-gate {
462*0Sstevel@tonic-gate 	commd_debug(dbc, "%s &res	= 0x%x\n", prefix, (int)res);
463*0Sstevel@tonic-gate 	commd_debug(dbc, "%s ID	= (%d, 0x%llx-%d)\n", prefix,
464*0Sstevel@tonic-gate 	    MSGID_ELEMS(res->mmr_msgid));
465*0Sstevel@tonic-gate 	commd_debug(dbc, "%s setno	= %d\n", prefix, res->mmr_setno);
466*0Sstevel@tonic-gate 	commd_debug(dbc, "%s type	= %d\n", prefix, res->mmr_msgtype);
467*0Sstevel@tonic-gate 	commd_debug(dbc, "%s flags	= 0x%x\n", prefix, res->mmr_flags);
468*0Sstevel@tonic-gate 	commd_debug(dbc, "%s comm_state= %d\n", prefix, res->mmr_comm_state);
469*0Sstevel@tonic-gate 	commd_debug(dbc, "%s exitval	= %d\n", prefix, res->mmr_exitval);
470*0Sstevel@tonic-gate 	commd_debug(dbc, "%s out_size	= %d\n", prefix, res->mmr_out_size);
471*0Sstevel@tonic-gate 	if (res->mmr_out_size)
472*0Sstevel@tonic-gate 		commd_debug(dbc, "%s out	= %s\n", prefix, res->mmr_out);
473*0Sstevel@tonic-gate 	commd_debug(dbc, "%s err_size	= %d\n", prefix, res->mmr_err_size);
474*0Sstevel@tonic-gate 	if (res->mmr_err_size)
475*0Sstevel@tonic-gate 		commd_debug(dbc, "%s err	= %s\n", prefix, res->mmr_err);
476*0Sstevel@tonic-gate }
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate /*
480*0Sstevel@tonic-gate  * Here we find out, where to store or find the results for a given msg.
481*0Sstevel@tonic-gate  *
482*0Sstevel@tonic-gate  * Per set we have a pointer to a three dimensional array:
483*0Sstevel@tonic-gate  * mct[set] -> mct_mce[NNODES][MD_MN_NCLASSES][MAX_SUBMESSAGES]
484*0Sstevel@tonic-gate  * So, for every possible node and for every possible class we can store
485*0Sstevel@tonic-gate  * MAX_SUBMESSAGES results.
486*0Sstevel@tonic-gate  * the way to find the correct index is
487*0Sstevel@tonic-gate  *	submessage +
488*0Sstevel@tonic-gate  *	class * MAX_SUBMESSAGES +
489*0Sstevel@tonic-gate  *	nodeid * MAX_SUBMESSAGES * MD_MN_NCLASSES.
490*0Sstevel@tonic-gate  *
491*0Sstevel@tonic-gate  * To find the correct address the index has to be multiplied
492*0Sstevel@tonic-gate  * by the size of one entry.
493*0Sstevel@tonic-gate  */
494*0Sstevel@tonic-gate static md_mn_mce_t *
495*0Sstevel@tonic-gate mdmn_get_mce_by_msg(md_mn_msg_t *msg)
496*0Sstevel@tonic-gate {
497*0Sstevel@tonic-gate 	set_t	setno = msg->msg_setno;
498*0Sstevel@tonic-gate 	int	nodeid = msg->msg_msgid.mid_nid;
499*0Sstevel@tonic-gate 	int	submsg = msg->msg_msgid.mid_smid;
500*0Sstevel@tonic-gate 	int	mct_index;
501*0Sstevel@tonic-gate 	off_t	mct_offset;
502*0Sstevel@tonic-gate 	md_mn_msgclass_t class;
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 	if (mct[setno] != NULL) {
505*0Sstevel@tonic-gate 		if (mdmn_init_set(setno, MDMN_SET_MCT) != 0) {
506*0Sstevel@tonic-gate 			return ((md_mn_mce_t *)MDMN_MCT_ERROR);
507*0Sstevel@tonic-gate 		}
508*0Sstevel@tonic-gate 	}
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 	if (submsg == 0) {
511*0Sstevel@tonic-gate 		class = mdmn_get_message_class(msg->msg_type);
512*0Sstevel@tonic-gate 	} else {
513*0Sstevel@tonic-gate 		class = msg->msg_msgid.mid_oclass;
514*0Sstevel@tonic-gate 	}
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 	mct_index = submsg +
517*0Sstevel@tonic-gate 		    class * MAX_SUBMESSAGES +
518*0Sstevel@tonic-gate 		    nodeid * MAX_SUBMESSAGES * MD_MN_NCLASSES;
519*0Sstevel@tonic-gate 
520*0Sstevel@tonic-gate 	mct_offset = mct_index * sizeof (md_mn_mce_t);
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 	/* LINTED Pointer alignment */
523*0Sstevel@tonic-gate 	return ((md_mn_mce_t *)((caddr_t)(mct[setno]) + mct_offset));
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 	/*
526*0Sstevel@tonic-gate 	 * the lint clean version would be:
527*0Sstevel@tonic-gate 	 * return (&(mct[setno]->mct_mce[0][0][0]) + mct_index);
528*0Sstevel@tonic-gate 	 * :-)
529*0Sstevel@tonic-gate 	 */
530*0Sstevel@tonic-gate }
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate /*
533*0Sstevel@tonic-gate  * mdmn_mark_completion(msg, result, flag)
534*0Sstevel@tonic-gate  * Stores the result of this message into the mmaped memory MCT[setno]
535*0Sstevel@tonic-gate  * In case the same message comes along a second time we will know that
536*0Sstevel@tonic-gate  * this message has already been processed and we can deliver the
537*0Sstevel@tonic-gate  * results immediately.
538*0Sstevel@tonic-gate  *
539*0Sstevel@tonic-gate  * Before a message handler is called, the message in the MCT is flagged
540*0Sstevel@tonic-gate  * as currently being processed (flag == MDMN_MCT_IN_PROGRESS).
541*0Sstevel@tonic-gate  * This we need so we don't start a second handler for the same message.
542*0Sstevel@tonic-gate  *
543*0Sstevel@tonic-gate  * After a message handler is completed, this routine is called with
544*0Sstevel@tonic-gate  * flag == MDMN_MCT_DONE and the appropriate result that we store in the MCT.
545*0Sstevel@tonic-gate  * As MCT[setno] is memory mapped to disks, this information is persistent
546*0Sstevel@tonic-gate  * even across a crash of the commd.
547*0Sstevel@tonic-gate  * It doesn't have to be persistent across a reboot, though.
548*0Sstevel@tonic-gate  *
549*0Sstevel@tonic-gate  * Returns MDMN_MCT_DONE in case of success
550*0Sstevel@tonic-gate  * Returns MDMN_MCT_ERROR in case of error creating the mct
551*0Sstevel@tonic-gate  */
552*0Sstevel@tonic-gate int
553*0Sstevel@tonic-gate mdmn_mark_completion(md_mn_msg_t *msg, md_mn_result_t *result, uint_t flag)
554*0Sstevel@tonic-gate {
555*0Sstevel@tonic-gate 	md_mn_mce_t	*mce;
556*0Sstevel@tonic-gate 	uint_t		offset_in_page;
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 	mce = mdmn_get_mce_by_msg(msg);
559*0Sstevel@tonic-gate 	if (mce == (md_mn_mce_t *)-1) {
560*0Sstevel@tonic-gate 		return (MDMN_MCT_ERROR);
561*0Sstevel@tonic-gate 	}
562*0Sstevel@tonic-gate 	offset_in_page = (uint_t)(caddr_t)mce % sysconf(_SC_PAGESIZE);
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 	memset(mce, 0, sizeof (md_mn_mce_t));
565*0Sstevel@tonic-gate 
566*0Sstevel@tonic-gate 	MSGID_COPY(&msg->msg_msgid, &mce->mce_result.mmr_msgid);
567*0Sstevel@tonic-gate 	if (flag == MDMN_MCT_IN_PROGRESS) {
568*0Sstevel@tonic-gate 		mce->mce_flags = MDMN_MCT_IN_PROGRESS;
569*0Sstevel@tonic-gate 		goto mmc_out;
570*0Sstevel@tonic-gate 	}
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 	/*
573*0Sstevel@tonic-gate 	 * In case the message flags indicate that the result should not be
574*0Sstevel@tonic-gate 	 * stored in the MCT, we return a MDMN_MCT_NOT_DONE,
575*0Sstevel@tonic-gate 	 * so the message will be processed at any rate,
576*0Sstevel@tonic-gate 	 * even if we process this message twice.
577*0Sstevel@tonic-gate 	 * this makes sense if the result of the message is a dynamic status
578*0Sstevel@tonic-gate 	 * and might have changed meanwhile.
579*0Sstevel@tonic-gate 	 */
580*0Sstevel@tonic-gate 	if (msg->msg_flags & MD_MSGF_NO_MCT) {
581*0Sstevel@tonic-gate 		return (MDMN_MCT_DONE);
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	/* This msg is no longer in progress */
585*0Sstevel@tonic-gate 	mce->mce_flags = MDMN_MCT_DONE;
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 	mce->mce_result.mmr_msgtype	    = result->mmr_msgtype;
588*0Sstevel@tonic-gate 	mce->mce_result.mmr_setno	    = result->mmr_setno;
589*0Sstevel@tonic-gate 	mce->mce_result.mmr_flags	    = result->mmr_flags;
590*0Sstevel@tonic-gate 	mce->mce_result.mmr_sender	    = result->mmr_sender;
591*0Sstevel@tonic-gate 	mce->mce_result.mmr_failing_node    = result->mmr_failing_node;
592*0Sstevel@tonic-gate 	mce->mce_result.mmr_comm_state	    = result->mmr_comm_state;
593*0Sstevel@tonic-gate 	mce->mce_result.mmr_exitval	    = result->mmr_exitval;
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	/* if mmr_exitval is zero, we store stdout, otherwise stderr */
596*0Sstevel@tonic-gate 	if (result->mmr_exitval == 0) {
597*0Sstevel@tonic-gate 		if (result->mmr_out_size > 0) {
598*0Sstevel@tonic-gate 			memcpy(mce->mce_data, result->mmr_out,
599*0Sstevel@tonic-gate 			    result->mmr_out_size);
600*0Sstevel@tonic-gate 			mce->mce_result.mmr_out_size = result->mmr_out_size;
601*0Sstevel@tonic-gate 		}
602*0Sstevel@tonic-gate 	} else {
603*0Sstevel@tonic-gate 		if (result->mmr_err_size > 0) {
604*0Sstevel@tonic-gate 			mce->mce_result.mmr_err_size = result->mmr_err_size;
605*0Sstevel@tonic-gate 			memcpy(mce->mce_data, result->mmr_err,
606*0Sstevel@tonic-gate 			    result->mmr_err_size);
607*0Sstevel@tonic-gate 		}
608*0Sstevel@tonic-gate 	}
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 	dump_result(MD_MMV_PROC_S, "mdmn_mark_completion1", result);
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate mmc_out:
613*0Sstevel@tonic-gate 	/* now flush this entry to disk */
614*0Sstevel@tonic-gate 	msync((caddr_t)mce - offset_in_page,
615*0Sstevel@tonic-gate 	    sizeof (md_mn_mce_t) + offset_in_page, MS_SYNC);
616*0Sstevel@tonic-gate 	return (MDMN_MCT_DONE);
617*0Sstevel@tonic-gate }
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate /*
620*0Sstevel@tonic-gate  * mdmn_check_completion(msg, resultp)
621*0Sstevel@tonic-gate  * checks if msg has already been processed on this node, and if so copies
622*0Sstevel@tonic-gate  * the stored result to resultp.
623*0Sstevel@tonic-gate  *
624*0Sstevel@tonic-gate  * returns MDMN_MCT_DONE and the result filled out acurately in case the
625*0Sstevel@tonic-gate  *		msg has already been processed before
626*0Sstevel@tonic-gate  * returns MDMN_MCT_NOT_DONE if the message has not been processed before
627*0Sstevel@tonic-gate  * returns MDMN_MCT_IN_PROGRESS if the message is currently being processed
628*0Sstevel@tonic-gate  *	This can only occur on a slave node.
629*0Sstevel@tonic-gate  * return MDMN_MCT_ERROR in case of error creating the mct
630*0Sstevel@tonic-gate  */
631*0Sstevel@tonic-gate int
632*0Sstevel@tonic-gate mdmn_check_completion(md_mn_msg_t *msg, md_mn_result_t *result)
633*0Sstevel@tonic-gate {
634*0Sstevel@tonic-gate 	md_mn_mce_t	*mce;
635*0Sstevel@tonic-gate 	size_t		outsize;
636*0Sstevel@tonic-gate 	size_t		errsize;
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 	mce = mdmn_get_mce_by_msg(msg);
639*0Sstevel@tonic-gate 	if (mce == (md_mn_mce_t *)MDMN_MCT_ERROR) {
640*0Sstevel@tonic-gate 		return (MDMN_MCT_ERROR); /* what to do in that case ? */
641*0Sstevel@tonic-gate 	}
642*0Sstevel@tonic-gate 	if (MSGID_CMP(&(msg->msg_msgid), &(mce->mce_result.mmr_msgid))) {
643*0Sstevel@tonic-gate 		/* is the message completed, or in progress? */
644*0Sstevel@tonic-gate 		if (mce->mce_flags & MDMN_MCT_IN_PROGRESS) {
645*0Sstevel@tonic-gate 			return (MDMN_MCT_IN_PROGRESS);
646*0Sstevel@tonic-gate 		}
647*0Sstevel@tonic-gate 		/*
648*0Sstevel@tonic-gate 		 * See comment on MD_MSGF_NO_MCT above, if this flag is set
649*0Sstevel@tonic-gate 		 * for a message no result was stored and so the message has
650*0Sstevel@tonic-gate 		 * to be processed no matter if this is the 2nd time then.
651*0Sstevel@tonic-gate 		 */
652*0Sstevel@tonic-gate 		if (msg->msg_flags & MD_MSGF_NO_MCT) {
653*0Sstevel@tonic-gate 			return (MDMN_MCT_NOT_DONE);
654*0Sstevel@tonic-gate 		}
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 		/* Paranoia check: mce_flags must be MDMN_MCT_DONE here */
657*0Sstevel@tonic-gate 		if ((mce->mce_flags & MDMN_MCT_DONE) == 0) {
658*0Sstevel@tonic-gate 			commd_debug(MD_MMV_ALL,
659*0Sstevel@tonic-gate 			    "mdmn_check_completion: msg not done and not in "
660*0Sstevel@tonic-gate 			    "progress! ID = (%d, 0x%llx-%d)\n",
661*0Sstevel@tonic-gate 			    MSGID_ELEMS(msg->msg_msgid));
662*0Sstevel@tonic-gate 			return (MDMN_MCT_NOT_DONE);
663*0Sstevel@tonic-gate 		}
664*0Sstevel@tonic-gate 		/*
665*0Sstevel@tonic-gate 		 * Already processed.
666*0Sstevel@tonic-gate 		 * Copy saved results data;
667*0Sstevel@tonic-gate 		 * return only a pointer to any output.
668*0Sstevel@tonic-gate 		 */
669*0Sstevel@tonic-gate 		MSGID_COPY(&(mce->mce_result.mmr_msgid), &result->mmr_msgid);
670*0Sstevel@tonic-gate 		result->mmr_msgtype	    = mce->mce_result.mmr_msgtype;
671*0Sstevel@tonic-gate 		result->mmr_setno	    = mce->mce_result.mmr_setno;
672*0Sstevel@tonic-gate 		result->mmr_flags	    = mce->mce_result.mmr_flags;
673*0Sstevel@tonic-gate 		result->mmr_sender	    = mce->mce_result.mmr_sender;
674*0Sstevel@tonic-gate 		result->mmr_failing_node    = mce->mce_result.mmr_failing_node;
675*0Sstevel@tonic-gate 		result->mmr_comm_state	    = mce->mce_result.mmr_comm_state;
676*0Sstevel@tonic-gate 		result->mmr_exitval	    = mce->mce_result.mmr_exitval;
677*0Sstevel@tonic-gate 		result->mmr_err		    = NULL;
678*0Sstevel@tonic-gate 		result->mmr_out		    = NULL;
679*0Sstevel@tonic-gate 		outsize = result->mmr_out_size = mce->mce_result.mmr_out_size;
680*0Sstevel@tonic-gate 		errsize = result->mmr_err_size = mce->mce_result.mmr_err_size;
681*0Sstevel@tonic-gate 		/*
682*0Sstevel@tonic-gate 		 * if the exit val is zero only stdout was stored (if any)
683*0Sstevel@tonic-gate 		 * otherwise only stderr was stored (if any)
684*0Sstevel@tonic-gate 		 */
685*0Sstevel@tonic-gate 		if (result->mmr_exitval == 0) {
686*0Sstevel@tonic-gate 			if (outsize != 0) {
687*0Sstevel@tonic-gate 				result->mmr_out = Zalloc(outsize);
688*0Sstevel@tonic-gate 				memcpy(result->mmr_out, mce->mce_data, outsize);
689*0Sstevel@tonic-gate 			}
690*0Sstevel@tonic-gate 		} else {
691*0Sstevel@tonic-gate 			if (errsize != 0) {
692*0Sstevel@tonic-gate 				result->mmr_err = Zalloc(errsize);
693*0Sstevel@tonic-gate 				memcpy(result->mmr_err, mce->mce_data, errsize);
694*0Sstevel@tonic-gate 			}
695*0Sstevel@tonic-gate 		}
696*0Sstevel@tonic-gate 		commd_debug(MD_MMV_MISC,
697*0Sstevel@tonic-gate 			    "mdmn_check_completion: msg already processed \n");
698*0Sstevel@tonic-gate 		dump_result(MD_MMV_MISC, "mdmn_check_completion", result);
699*0Sstevel@tonic-gate 		return (MDMN_MCT_DONE);
700*0Sstevel@tonic-gate 	}
701*0Sstevel@tonic-gate 	commd_debug(MD_MMV_MISC,
702*0Sstevel@tonic-gate 		    "mdmn_check_completion: msg not yet processed\n");
703*0Sstevel@tonic-gate 	return (MDMN_MCT_NOT_DONE);
704*0Sstevel@tonic-gate }
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate /*
709*0Sstevel@tonic-gate  * check_license(rqstp, chknid)
710*0Sstevel@tonic-gate  *
711*0Sstevel@tonic-gate  * Is this RPC request sent from a licensed host?
712*0Sstevel@tonic-gate  *
713*0Sstevel@tonic-gate  * If chknid is non-zero, the caller of check_license() knows the ID of
714*0Sstevel@tonic-gate  * the sender. Then we check just the one entry of licensed_nodes[]
715*0Sstevel@tonic-gate  *
716*0Sstevel@tonic-gate  * If chknid is zero, the sender is not known. In that case the sender must be
717*0Sstevel@tonic-gate  * the local node.
718*0Sstevel@tonic-gate  *
719*0Sstevel@tonic-gate  * If the host is licensed, return TRUE, else return FALSE
720*0Sstevel@tonic-gate  */
721*0Sstevel@tonic-gate bool_t
722*0Sstevel@tonic-gate check_license(struct svc_req *rqstp, md_mn_nodeid_t chknid)
723*0Sstevel@tonic-gate {
724*0Sstevel@tonic-gate 	char		buf[INET6_ADDRSTRLEN];
725*0Sstevel@tonic-gate 	void		*caller = NULL;
726*0Sstevel@tonic-gate 	in_addr_t	caller_ipv4;
727*0Sstevel@tonic-gate 	in6_addr_t	caller_ipv6;
728*0Sstevel@tonic-gate 	struct sockaddr	*ca;
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	ca = (struct sockaddr *)(void *)svc_getrpccaller(rqstp->rq_xprt)->buf;
732*0Sstevel@tonic-gate 
733*0Sstevel@tonic-gate 	if (ca->sa_family == AF_INET) {
734*0Sstevel@tonic-gate 		caller_ipv4 =
735*0Sstevel@tonic-gate 		    ((struct sockaddr_in *)(void *)ca)->sin_addr.s_addr;
736*0Sstevel@tonic-gate 		caller = (void *)&caller_ipv4;
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 		if (chknid == 0) {
739*0Sstevel@tonic-gate 			/* check against local node */
740*0Sstevel@tonic-gate 			if (caller_ipv4 == htonl(INADDR_LOOPBACK)) {
741*0Sstevel@tonic-gate 				return (TRUE);
742*0Sstevel@tonic-gate 
743*0Sstevel@tonic-gate 			}
744*0Sstevel@tonic-gate 		} else {
745*0Sstevel@tonic-gate 			/* check against one specific node */
746*0Sstevel@tonic-gate 			if ((caller_ipv4 == licensed_nodes[chknid].lip_ipv4) &&
747*0Sstevel@tonic-gate 			    (licensed_nodes[chknid].lip_family == AF_INET)) {
748*0Sstevel@tonic-gate 				return (TRUE);
749*0Sstevel@tonic-gate 			} else {
750*0Sstevel@tonic-gate 				commd_debug(MD_MMV_MISC,
751*0Sstevel@tonic-gate 				    "Bad attempt from %x ln[%d]=%x\n",
752*0Sstevel@tonic-gate 				    caller_ipv4, chknid,
753*0Sstevel@tonic-gate 				    licensed_nodes[chknid].lip_ipv4);
754*0Sstevel@tonic-gate 			}
755*0Sstevel@tonic-gate 		}
756*0Sstevel@tonic-gate 	} else if (ca->sa_family == AF_INET6) {
757*0Sstevel@tonic-gate 		caller_ipv6 = ((struct sockaddr_in6 *)(void *)ca)->sin6_addr;
758*0Sstevel@tonic-gate 		caller = (void *)&caller_ipv6;
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 		if (chknid == 0) {
761*0Sstevel@tonic-gate 			/* check against local node */
762*0Sstevel@tonic-gate 			if (IN6_IS_ADDR_LOOPBACK(&caller_ipv6)) {
763*0Sstevel@tonic-gate 				return (TRUE);
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 			}
766*0Sstevel@tonic-gate 		} else {
767*0Sstevel@tonic-gate 			/* check against one specific node */
768*0Sstevel@tonic-gate 			if (IN6_ARE_ADDR_EQUAL(&caller_ipv6,
769*0Sstevel@tonic-gate 			    &(licensed_nodes[chknid].lip_ipv6)) &&
770*0Sstevel@tonic-gate 			    (licensed_nodes[chknid].lip_family == AF_INET6)) {
771*0Sstevel@tonic-gate 				return (TRUE);
772*0Sstevel@tonic-gate 			}
773*0Sstevel@tonic-gate 		}
774*0Sstevel@tonic-gate 	}
775*0Sstevel@tonic-gate 	/* if  we are here, we were contacted by an unlicensed node */
776*0Sstevel@tonic-gate 	commd_debug(MD_MMV_SYSLOG,
777*0Sstevel@tonic-gate 	    "Bad attempt to contact rpc.mdcommd from %s\n",
778*0Sstevel@tonic-gate 	    caller ?
779*0Sstevel@tonic-gate 	    inet_ntop(ca->sa_family, caller, buf, INET6_ADDRSTRLEN) :
780*0Sstevel@tonic-gate 	    "unknown");
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 	return (FALSE);
783*0Sstevel@tonic-gate }
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate /*
786*0Sstevel@tonic-gate  * Add a node to the list of licensed nodes.
787*0Sstevel@tonic-gate  *
788*0Sstevel@tonic-gate  * Only IPv4 is currently supported.
789*0Sstevel@tonic-gate  * for IPv6, we need to change md_mnnode_desc.
790*0Sstevel@tonic-gate  */
791*0Sstevel@tonic-gate void
792*0Sstevel@tonic-gate add_license(md_mnnode_desc *node)
793*0Sstevel@tonic-gate {
794*0Sstevel@tonic-gate 	md_mn_nodeid_t nid = node->nd_nodeid;
795*0Sstevel@tonic-gate 	char		buf[INET6_ADDRSTRLEN];
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 	/*
798*0Sstevel@tonic-gate 	 * If this node is not yet licensed, do it now.
799*0Sstevel@tonic-gate 	 * For now only IPv4 addresses are supported.
800*0Sstevel@tonic-gate 	 */
801*0Sstevel@tonic-gate 	commd_debug(MD_MMV_MISC, "add_lic(%s): ln[%d]=%s, lnc[%d]=%d\n",
802*0Sstevel@tonic-gate 	    node->nd_priv_ic, nid,
803*0Sstevel@tonic-gate 	    inet_ntop(AF_INET, (void *)&licensed_nodes[nid].lip_ipv4,
804*0Sstevel@tonic-gate 	    buf, INET6_ADDRSTRLEN), nid, licensed_nodes[nid].lip_cnt);
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	if (licensed_nodes[nid].lip_ipv4 == (in_addr_t)0) {
807*0Sstevel@tonic-gate 		licensed_nodes[nid].lip_family = AF_INET; /* IPv4 */
808*0Sstevel@tonic-gate 		licensed_nodes[nid].lip_ipv4 = inet_addr(node->nd_priv_ic);
809*0Sstevel@tonic-gate 		/* keep track of the last entry for faster search */
810*0Sstevel@tonic-gate 		if (nid > maxlicnodes)
811*0Sstevel@tonic-gate 			maxlicnodes = nid;
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate 	}
814*0Sstevel@tonic-gate 	/* in any case bump up the reference count */
815*0Sstevel@tonic-gate 	licensed_nodes[nid].lip_cnt++;
816*0Sstevel@tonic-gate }
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate /*
819*0Sstevel@tonic-gate  * lower the reference count for one node.
820*0Sstevel@tonic-gate  * If that drops to zero, remove the node from the list of licensed nodes
821*0Sstevel@tonic-gate  *
822*0Sstevel@tonic-gate  * Only IPv4 is currently supported.
823*0Sstevel@tonic-gate  * for IPv6, we need to change md_mnnode_desc.
824*0Sstevel@tonic-gate  */
825*0Sstevel@tonic-gate void
826*0Sstevel@tonic-gate rem_license(md_mnnode_desc *node)
827*0Sstevel@tonic-gate {
828*0Sstevel@tonic-gate 	md_mn_nodeid_t nid = node->nd_nodeid;
829*0Sstevel@tonic-gate 	char		buf[INET6_ADDRSTRLEN];
830*0Sstevel@tonic-gate 
831*0Sstevel@tonic-gate 	commd_debug(MD_MMV_MISC, "rem_lic(%s): ln[%d]=%s, lnc[%d]=%d\n",
832*0Sstevel@tonic-gate 	    node->nd_priv_ic, nid,
833*0Sstevel@tonic-gate 	    inet_ntop(AF_INET, (void *)&licensed_nodes[nid].lip_ipv4, buf,
834*0Sstevel@tonic-gate 	    INET6_ADDRSTRLEN), nid, licensed_nodes[nid].lip_cnt);
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 	assert(licensed_nodes[nid].lip_cnt > 0);
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate 	/*
839*0Sstevel@tonic-gate 	 * If this was the last reference to that node, it's license expires
840*0Sstevel@tonic-gate 	 * For now only IPv4 addresses are supported.
841*0Sstevel@tonic-gate 	 */
842*0Sstevel@tonic-gate 	if (--licensed_nodes[nid].lip_cnt == 0) {
843*0Sstevel@tonic-gate 		licensed_nodes[nid].lip_ipv4 = (in_addr_t)0;
844*0Sstevel@tonic-gate 	}
845*0Sstevel@tonic-gate }
846