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