Print this page
6659 nvlist_free(NULL) is a no-op
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/fm/fmd/common/fmd_xprt.c
+++ new/usr/src/cmd/fm/fmd/common/fmd_xprt.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * FMD Transport Subsystem
28 28 *
29 29 * A transport module uses some underlying mechanism to transport events.
30 30 * This mechanism may use any underlying link-layer protocol and may support
31 31 * additional link-layer packets unrelated to FMA. Some appropriate link-
32 32 * layer mechanism to create the underlying connection is expected to be
33 33 * called prior to calling fmd_xprt_open() itself. Alternatively, a transport
34 34 * may be created in the suspended state by specifying the FMD_XPRT_SUSPENDED
35 35 * flag as part of the call to fmd_xprt_open(), and then may be resumed later.
36 36 * The underlying transport mechanism is *required* to provide ordering: that
37 37 * is, the sequences of bytes written across the transport must be read by
38 38 * the remote peer in the order that they are written, even across separate
39 39 * calls to fmdo_send(). As an example, the Internet TCP protocol would be
40 40 * a valid transport as it guarantees ordering, whereas the Internet UDP
41 41 * protocol would not because UDP datagrams may be delivered in any order
42 42 * as a result of delays introduced when datagrams pass through routers.
43 43 *
44 44 * Similar to sending events, a transport module receives events that are from
45 45 * its peer remote endpoint using some transport-specific mechanism that is
46 46 * unknown to FMD. As each event is received, the transport module is
47 47 * responsible for constructing a valid nvlist_t object from the data and then
48 48 * calling fmd_xprt_post() to post the event to the containing FMD's dispatch
49 49 * queue, making it available to all local modules that are not transport
50 50 * modules that have subscribed to the event.
51 51 *
52 52 * The following state machine is used for each transport. The initial state
53 53 * is either SYN, ACK, or RUN, depending on the flags specified to xprt_create.
54 54 *
55 55 * FMD_XPRT_ACCEPT !FMD_XPRT_ACCEPT
56 56 * | |
57 57 * waiting +--v--+ +--v--+ waiting
58 58 * for syn | SYN |--+ --+| ACK | for ack
59 59 * event +-----+ \ / +-----+ event
60 60 * | \ / |
61 61 * drop all +--v--+ X +--v--+ send subscriptions,
62 62 * events | ERR |<---+ +--->| SUB | recv subscriptions,
63 63 * +-----+ +-----+ wait for run event
64 64 * ^ |
65 65 * | +-----+ |
66 66 * +-----| RUN |<----+
67 67 * +--^--+
68 68 * |
69 69 * FMD_XPRT_RDONLY
70 70 *
71 71 * When fmd_xprt_open() is called without FMD_XPRT_ACCEPT, the Common Transport
72 72 * Layer enqueues a "syn" event for the module in its event queue and sets the
73 73 * state to ACK. In state ACK, we are waiting for the transport to get an
74 74 * "ack" event and call fmd_xprt_post() on this event. Other events will be
75 75 * discarded. If an "ack" is received, we transition to state SUB. If a
76 76 * configurable timeout occurs or if the "ack" is invalid (e.g. invalid version
77 77 * exchange), we transition to state ERR. Once in state ERR, no further
78 78 * operations are valid except fmd_xprt_close() and fmd_xprt_error() will
79 79 * return a non-zero value to the caller indicating the transport has failed.
80 80 *
81 81 * When fmd_xprt_open() is called with FMD_XPRT_ACCEPT, the Common Transport
82 82 * Layer assumes this transport is being used to accept a virtual connection
83 83 * from a remote peer that is sending a "syn", and sets the initial state to
84 84 * SYN. In this state, the transport waits for a "syn" event, validates it,
85 85 * and then transitions to state SUB if it is valid or state ERR if it is not.
86 86 *
87 87 * Once in state SUB, the transport module is expected to receive a sequence of
88 88 * zero or more "subscribe" events from the remote peer, followed by a "run"
89 89 * event. Once in state RUN, the transport is active and any events can be
90 90 * sent or received. The transport module is free to call fmd_xprt_close()
91 91 * from any state. The fmd_xprt_error() function will return zero if the
92 92 * transport is not in the ERR state, or non-zero if it is in the ERR state.
93 93 *
94 94 * Once the state machine reaches RUN, other FMA protocol events can be sent
95 95 * and received across the transport in addition to the various control events.
96 96 *
97 97 * Table of Common Transport Layer Control Events
98 98 * ==============================================
99 99 *
100 100 * FMA Class Payload
101 101 * --------- -------
102 102 * resource.fm.xprt.uuclose string (uuid of case)
103 103 * resource.fm.xprt.uuresolved string (uuid of case)
104 104 * resource.fm.xprt.updated string (uuid of case)
105 105 * resource.fm.xprt.subscribe string (class pattern)
106 106 * resource.fm.xprt.unsubscribe string (class pattern)
107 107 * resource.fm.xprt.unsuback string (class pattern)
108 108 * resource.fm.xprt.syn version information
109 109 * resource.fm.xprt.ack version information
110 110 * resource.fm.xprt.run version information
111 111 *
112 112 * Control events are used to add and delete proxy subscriptions on the remote
113 113 * transport peer module, and to set up connections. When a "syn" event is
114 114 * sent, FMD will include in the payload the highest version of the FMA event
115 115 * protocol that is supported by the sender. When a "syn" event is received,
116 116 * the receiving FMD will use the minimum of this version and its version of
117 117 * the protocol, and reply with this new minimum version in the "ack" event.
118 118 * The receiver will then use this new minimum for subsequent event semantics.
119 119 */
120 120
121 121 #include <sys/fm/protocol.h>
122 122 #include <strings.h>
123 123 #include <limits.h>
124 124
125 125 #include <fmd_alloc.h>
126 126 #include <fmd_error.h>
127 127 #include <fmd_conf.h>
128 128 #include <fmd_subr.h>
129 129 #include <fmd_string.h>
130 130 #include <fmd_protocol.h>
131 131 #include <fmd_thread.h>
132 132 #include <fmd_eventq.h>
133 133 #include <fmd_dispq.h>
134 134 #include <fmd_ctl.h>
135 135 #include <fmd_log.h>
136 136 #include <fmd_ustat.h>
137 137 #include <fmd_case.h>
138 138 #include <fmd_api.h>
139 139 #include <fmd_fmri.h>
140 140 #include <fmd_asru.h>
141 141 #include <fmd_xprt.h>
142 142
143 143 #include <fmd.h>
144 144
145 145 /*
146 146 * The states shown above in the transport state machine diagram are encoded
147 147 * using arrays of class patterns and a corresponding action function. These
148 148 * arrays are then passed to fmd_xprt_transition() to change transport states.
149 149 */
150 150
151 151 const fmd_xprt_rule_t _fmd_xprt_state_syn[] = {
152 152 { "resource.fm.xprt.syn", fmd_xprt_event_syn },
153 153 { "*", fmd_xprt_event_error },
154 154 { NULL, NULL }
155 155 };
156 156
157 157 const fmd_xprt_rule_t _fmd_xprt_state_ack[] = {
158 158 { "resource.fm.xprt.ack", fmd_xprt_event_ack },
159 159 { "*", fmd_xprt_event_error },
160 160 };
161 161
162 162 const fmd_xprt_rule_t _fmd_xprt_state_err[] = {
163 163 { "*", fmd_xprt_event_drop },
164 164 { NULL, NULL }
165 165 };
166 166
167 167 const fmd_xprt_rule_t _fmd_xprt_state_sub[] = {
168 168 { "resource.fm.xprt.subscribe", fmd_xprt_event_sub },
169 169 { "resource.fm.xprt.run", fmd_xprt_event_run },
170 170 { "resource.fm.xprt.*", fmd_xprt_event_error },
171 171 { "*", fmd_xprt_event_drop },
172 172 { NULL, NULL }
173 173 };
174 174
175 175 const fmd_xprt_rule_t _fmd_xprt_state_run[] = {
176 176 { "resource.fm.xprt.subscribe", fmd_xprt_event_sub },
177 177 { "resource.fm.xprt.unsubscribe", fmd_xprt_event_unsub },
178 178 { "resource.fm.xprt.unsuback", fmd_xprt_event_unsuback },
179 179 { "resource.fm.xprt.uuclose", fmd_xprt_event_uuclose },
180 180 { "resource.fm.xprt.uuresolved", fmd_xprt_event_uuresolved },
181 181 { "resource.fm.xprt.updated", fmd_xprt_event_updated },
182 182 { "resource.fm.xprt.*", fmd_xprt_event_error },
183 183 { NULL, NULL }
184 184 };
185 185
186 186 /*
187 187 * Template for per-transport statistics installed by fmd on behalf of each
188 188 * transport. These are used to initialize the per-transport xi_stats. For
189 189 * each statistic, the name is prepended with "fmd.xprt.%u", where %u is the
190 190 * transport ID (xi_id) and then are inserted into the per-module stats hash.
191 191 * The values in this array must match fmd_xprt_stat_t from <fmd_xprt.h>.
192 192 */
193 193 static const fmd_xprt_stat_t _fmd_xprt_stat_tmpl = {
194 194 {
195 195 { "dispatched", FMD_TYPE_UINT64, "total events dispatched to transport" },
196 196 { "dequeued", FMD_TYPE_UINT64, "total events dequeued by transport" },
197 197 { "prdequeued", FMD_TYPE_UINT64, "protocol events dequeued by transport" },
198 198 { "dropped", FMD_TYPE_UINT64, "total events dropped on queue overflow" },
199 199 { "wcnt", FMD_TYPE_UINT32, "count of events waiting on queue" },
200 200 { "wtime", FMD_TYPE_TIME, "total wait time on queue" },
201 201 { "wlentime", FMD_TYPE_TIME, "total wait length * time product" },
202 202 { "wlastupdate", FMD_TYPE_TIME, "hrtime of last wait queue update" },
203 203 { "dtime", FMD_TYPE_TIME, "total processing time after dequeue" },
204 204 { "dlastupdate", FMD_TYPE_TIME, "hrtime of last event dequeue completion" },
205 205 },
206 206 { "module", FMD_TYPE_STRING, "module that owns this transport" },
207 207 { "authority", FMD_TYPE_STRING, "authority associated with this transport" },
208 208 { "state", FMD_TYPE_STRING, "current transport state" },
209 209 { "received", FMD_TYPE_UINT64, "events received by transport" },
210 210 { "discarded", FMD_TYPE_UINT64, "bad events discarded by transport" },
211 211 { "retried", FMD_TYPE_UINT64, "retries requested of transport" },
212 212 { "replayed", FMD_TYPE_UINT64, "events replayed by transport" },
213 213 { "lost", FMD_TYPE_UINT64, "events lost by transport" },
214 214 { "timeouts", FMD_TYPE_UINT64, "events received by transport with ttl=0" },
215 215 { "subscriptions", FMD_TYPE_UINT64, "subscriptions registered to transport" },
216 216 };
217 217
218 218 static void
219 219 fmd_xprt_class_hash_create(fmd_xprt_class_hash_t *xch, fmd_eventq_t *eq)
220 220 {
221 221 uint_t hashlen = fmd.d_str_buckets;
222 222
223 223 xch->xch_queue = eq;
224 224 xch->xch_hashlen = hashlen;
225 225 xch->xch_hash = fmd_zalloc(sizeof (void *) * hashlen, FMD_SLEEP);
226 226 }
227 227
228 228 static void
229 229 fmd_xprt_class_hash_destroy(fmd_xprt_class_hash_t *xch)
230 230 {
231 231 fmd_eventq_t *eq = xch->xch_queue;
232 232 fmd_xprt_class_t *xcp, *ncp;
233 233 uint_t i;
234 234
235 235 for (i = 0; i < xch->xch_hashlen; i++) {
236 236 for (xcp = xch->xch_hash[i]; xcp != NULL; xcp = ncp) {
237 237 ncp = xcp->xc_next;
238 238
239 239 if (eq != NULL)
240 240 fmd_dispq_delete(fmd.d_disp, eq, xcp->xc_class);
241 241
242 242 fmd_strfree(xcp->xc_class);
243 243 fmd_free(xcp, sizeof (fmd_xprt_class_t));
244 244 }
245 245 }
246 246
247 247 fmd_free(xch->xch_hash, sizeof (void *) * xch->xch_hashlen);
248 248 }
249 249
250 250 /*
251 251 * Insert the specified class into the specified class hash, and return the
252 252 * reference count. A return value of one indicates this is the first insert.
253 253 * If an eventq is associated with the hash, insert a dispq subscription for it.
254 254 */
255 255 static uint_t
256 256 fmd_xprt_class_hash_insert(fmd_xprt_impl_t *xip,
257 257 fmd_xprt_class_hash_t *xch, const char *class)
258 258 {
259 259 uint_t h = fmd_strhash(class) % xch->xch_hashlen;
260 260 fmd_xprt_class_t *xcp;
261 261
262 262 ASSERT(MUTEX_HELD(&xip->xi_lock));
263 263
264 264 for (xcp = xch->xch_hash[h]; xcp != NULL; xcp = xcp->xc_next) {
265 265 if (strcmp(class, xcp->xc_class) == 0)
266 266 return (++xcp->xc_refs);
267 267 }
268 268
269 269 xcp = fmd_alloc(sizeof (fmd_xprt_class_t), FMD_SLEEP);
270 270 xcp->xc_class = fmd_strdup(class, FMD_SLEEP);
271 271 xcp->xc_next = xch->xch_hash[h];
272 272 xcp->xc_refs = 1;
273 273 xch->xch_hash[h] = xcp;
274 274
275 275 if (xch->xch_queue != NULL)
276 276 fmd_dispq_insert(fmd.d_disp, xch->xch_queue, class);
277 277
278 278 return (xcp->xc_refs);
279 279 }
280 280
281 281 /*
282 282 * Delete the specified class from the specified class hash, and return the
283 283 * reference count. A return value of zero indicates the class was deleted.
284 284 * If an eventq is associated with the hash, delete the dispq subscription.
285 285 */
286 286 static uint_t
287 287 fmd_xprt_class_hash_delete(fmd_xprt_impl_t *xip,
288 288 fmd_xprt_class_hash_t *xch, const char *class)
289 289 {
290 290 uint_t h = fmd_strhash(class) % xch->xch_hashlen;
291 291 fmd_xprt_class_t *xcp, **pp;
292 292
293 293 ASSERT(MUTEX_HELD(&xip->xi_lock));
294 294 pp = &xch->xch_hash[h];
295 295
296 296 for (xcp = *pp; xcp != NULL; xcp = xcp->xc_next) {
297 297 if (strcmp(class, xcp->xc_class) == 0)
298 298 break;
299 299 else
300 300 pp = &xcp->xc_next;
301 301 }
302 302
303 303 if (xcp == NULL)
304 304 return (-1U); /* explicitly permit an invalid delete */
305 305
306 306 if (--xcp->xc_refs != 0)
307 307 return (xcp->xc_refs);
308 308
309 309 ASSERT(xcp->xc_refs == 0);
310 310 *pp = xcp->xc_next;
311 311
312 312 fmd_strfree(xcp->xc_class);
313 313 fmd_free(xcp, sizeof (fmd_xprt_class_t));
314 314
315 315 if (xch->xch_queue != NULL)
316 316 fmd_dispq_delete(fmd.d_disp, xch->xch_queue, class);
317 317
318 318 return (0);
319 319 }
320 320
321 321 /*
322 322 * Queue subscribe events for the specified transport corresponding to all of
323 323 * the active module subscriptions. This is an extremely heavyweight operation
324 324 * that we expect to take place rarely (i.e. when loading a transport module
325 325 * or when it establishes a connection). We lock all of the known modules to
326 326 * prevent them from adding or deleting subscriptions, then snapshot their
327 327 * subscriptions, and then unlock all of the modules. We hold the modhash
328 328 * lock for the duration of this operation to prevent new modules from loading.
329 329 */
330 330 static void
331 331 fmd_xprt_subscribe_modhash(fmd_xprt_impl_t *xip, fmd_modhash_t *mhp)
332 332 {
333 333 fmd_xprt_t *xp = (fmd_xprt_t *)xip;
334 334 const fmd_conf_path_t *pap;
335 335 fmd_module_t *mp;
336 336 uint_t i, j;
337 337
338 338 (void) pthread_rwlock_rdlock(&mhp->mh_lock);
339 339
340 340 for (i = 0; i < mhp->mh_hashlen; i++) {
341 341 for (mp = mhp->mh_hash[i]; mp != NULL; mp = mp->mod_next)
342 342 fmd_module_lock(mp);
343 343 }
344 344
345 345 (void) pthread_mutex_lock(&xip->xi_lock);
346 346 ASSERT(!(xip->xi_flags & FMD_XPRT_SUBSCRIBER));
347 347 xip->xi_flags |= FMD_XPRT_SUBSCRIBER;
348 348 (void) pthread_mutex_unlock(&xip->xi_lock);
349 349
350 350 for (i = 0; i < mhp->mh_hashlen; i++) {
351 351 for (mp = mhp->mh_hash[i]; mp != NULL; mp = mp->mod_next) {
352 352 (void) fmd_conf_getprop(mp->mod_conf,
353 353 FMD_PROP_SUBSCRIPTIONS, &pap);
354 354 for (j = 0; j < pap->cpa_argc; j++)
355 355 fmd_xprt_subscribe(xp, pap->cpa_argv[j]);
356 356 }
357 357 }
358 358
359 359 for (i = 0; i < mhp->mh_hashlen; i++) {
360 360 for (mp = mhp->mh_hash[i]; mp != NULL; mp = mp->mod_next)
361 361 fmd_module_unlock(mp);
362 362 }
363 363
364 364 (void) pthread_rwlock_unlock(&mhp->mh_lock);
365 365 }
366 366
367 367 static void
368 368 fmd_xprt_transition(fmd_xprt_impl_t *xip,
369 369 const fmd_xprt_rule_t *state, const char *tag)
370 370 {
371 371 fmd_xprt_t *xp = (fmd_xprt_t *)xip;
372 372 fmd_event_t *e;
373 373 nvlist_t *nvl;
374 374 char *s;
375 375
376 376 TRACE((FMD_DBG_XPRT, "xprt %u -> %s\n", xip->xi_id, tag));
377 377
378 378 xip->xi_state = state;
379 379 s = fmd_strdup(tag, FMD_SLEEP);
380 380
381 381 (void) pthread_mutex_lock(&xip->xi_stats_lock);
382 382 fmd_strfree(xip->xi_stats->xs_state.fmds_value.str);
383 383 xip->xi_stats->xs_state.fmds_value.str = s;
384 384 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
385 385
386 386 /*
387 387 * If we've reached the SUB state, take out the big hammer and snapshot
388 388 * all of the subscriptions of all of the loaded modules. Then queue a
389 389 * run event for our remote peer indicating that it can enter RUN.
390 390 */
391 391 if (state == _fmd_xprt_state_sub) {
392 392 fmd_xprt_subscribe_modhash(xip, fmd.d_mod_hash);
393 393
394 394 /*
395 395 * For read-write transports, we always want to set up remote
396 396 * subscriptions to the bultin list.* events, regardless of
397 397 * whether any agents have subscribed to them.
398 398 */
399 399 if (xip->xi_flags & FMD_XPRT_RDWR) {
400 400 fmd_xprt_subscribe(xp, FM_LIST_SUSPECT_CLASS);
401 401 fmd_xprt_subscribe(xp, FM_LIST_ISOLATED_CLASS);
402 402 fmd_xprt_subscribe(xp, FM_LIST_UPDATED_CLASS);
403 403 fmd_xprt_subscribe(xp, FM_LIST_RESOLVED_CLASS);
404 404 fmd_xprt_subscribe(xp, FM_LIST_REPAIRED_CLASS);
405 405 }
406 406
407 407 nvl = fmd_protocol_xprt_ctl(xip->xi_queue->eq_mod,
408 408 "resource.fm.xprt.run", xip->xi_version);
409 409
410 410 (void) nvlist_lookup_string(nvl, FM_CLASS, &s);
411 411 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s);
412 412 fmd_eventq_insert_at_time(xip->xi_queue, e);
413 413 }
414 414 }
415 415
416 416 static void
417 417 fmd_xprt_authupdate(fmd_xprt_impl_t *xip)
418 418 {
419 419 char *s = fmd_fmri_auth2str(xip->xi_auth);
420 420
421 421 (void) pthread_mutex_lock(&xip->xi_stats_lock);
422 422 fmd_strfree(xip->xi_stats->xs_authority.fmds_value.str);
423 423 xip->xi_stats->xs_authority.fmds_value.str = s;
424 424 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
425 425 }
426 426
427 427 static int
428 428 fmd_xprt_vmismatch(fmd_xprt_impl_t *xip, nvlist_t *nvl, uint_t *rversionp)
429 429 {
430 430 uint8_t rversion;
431 431
432 432 if (nvlist_lookup_uint8(nvl, FM_VERSION, &rversion) != 0) {
433 433 (void) pthread_mutex_lock(&xip->xi_stats_lock);
434 434 xip->xi_stats->xs_discarded.fmds_value.ui64++;
435 435 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
436 436
437 437 fmd_xprt_transition(xip, _fmd_xprt_state_err, "ERR");
438 438 return (1);
439 439 }
440 440
441 441 if (rversion > xip->xi_version) {
442 442 fmd_dprintf(FMD_DBG_XPRT, "xprt %u protocol mismatch: %u>%u\n",
443 443 xip->xi_id, rversion, xip->xi_version);
444 444
445 445 (void) pthread_mutex_lock(&xip->xi_stats_lock);
446 446 xip->xi_stats->xs_discarded.fmds_value.ui64++;
447 447 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
448 448
449 449 fmd_xprt_transition(xip, _fmd_xprt_state_err, "ERR");
450 450 return (1);
451 451 }
452 452
453 453 if (rversionp != NULL)
454 454 *rversionp = rversion;
455 455
456 456 return (0);
457 457 }
458 458
459 459 void
460 460 fmd_xprt_event_syn(fmd_xprt_impl_t *xip, nvlist_t *nvl)
461 461 {
462 462 fmd_event_t *e;
463 463 uint_t vers;
464 464 char *class;
465 465
466 466 if (fmd_xprt_vmismatch(xip, nvl, &vers))
467 467 return; /* transitioned to error state */
468 468
469 469 /*
470 470 * If the transport module didn't specify an authority, extract the
471 471 * one that is passed along with the xprt.syn event and use that.
472 472 */
473 473 if (xip->xi_auth == NULL &&
474 474 nvlist_lookup_nvlist(nvl, FM_RSRC_RESOURCE, &nvl) == 0 &&
475 475 nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &nvl) == 0) {
476 476 (void) nvlist_xdup(nvl, &xip->xi_auth, &fmd.d_nva);
477 477 fmd_xprt_authupdate(xip);
478 478 }
479 479
480 480 nvl = fmd_protocol_xprt_ctl(xip->xi_queue->eq_mod,
481 481 "resource.fm.xprt.ack", xip->xi_version);
482 482
483 483 (void) nvlist_lookup_string(nvl, FM_CLASS, &class);
484 484 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class);
485 485 fmd_eventq_insert_at_time(xip->xi_queue, e);
486 486
487 487 xip->xi_version = MIN(FM_RSRC_XPRT_VERSION, vers);
488 488 fmd_xprt_transition(xip, _fmd_xprt_state_sub, "SUB");
489 489 }
490 490
491 491 void
492 492 fmd_xprt_event_ack(fmd_xprt_impl_t *xip, nvlist_t *nvl)
493 493 {
494 494 uint_t vers;
495 495
496 496 if (fmd_xprt_vmismatch(xip, nvl, &vers))
497 497 return; /* transitioned to error state */
498 498
499 499 /*
500 500 * If the transport module didn't specify an authority, extract the
501 501 * one that is passed along with the xprt.syn event and use that.
502 502 */
503 503 if (xip->xi_auth == NULL &&
504 504 nvlist_lookup_nvlist(nvl, FM_RSRC_RESOURCE, &nvl) == 0 &&
505 505 nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &nvl) == 0) {
506 506 (void) nvlist_xdup(nvl, &xip->xi_auth, &fmd.d_nva);
507 507 fmd_xprt_authupdate(xip);
508 508 }
509 509
510 510 xip->xi_version = MIN(FM_RSRC_XPRT_VERSION, vers);
511 511 fmd_xprt_transition(xip, _fmd_xprt_state_sub, "SUB");
512 512 }
513 513
514 514 /*
515 515 * Upon transition to RUN, we take every solved case and resend a list.suspect
516 516 * event for it to our remote peer. If a case transitions from solved to a
517 517 * future state (CLOSE_WAIT, CLOSED, or REPAIRED) while we are iterating over
518 518 * the case hash, we will get it as part of examining the resource cache, next.
519 519 */
520 520 static void
521 521 fmd_xprt_send_case(fmd_case_t *cp, void *arg)
522 522 {
523 523 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
524 524 fmd_xprt_impl_t *xip = arg;
525 525
526 526 fmd_event_t *e;
527 527 nvlist_t *nvl;
528 528 char *class;
529 529
530 530 if (cip->ci_state != FMD_CASE_SOLVED)
531 531 return;
532 532
533 533 nvl = fmd_case_mkevent(cp, FM_LIST_SUSPECT_CLASS);
534 534 (void) nvlist_lookup_string(nvl, FM_CLASS, &class);
535 535 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class);
536 536
537 537 fmd_dprintf(FMD_DBG_XPRT, "re-send %s for %s to transport %u\n",
538 538 FM_LIST_SUSPECT_CLASS, cip->ci_uuid, xip->xi_id);
539 539
540 540 fmd_dispq_dispatch_gid(fmd.d_disp, e, class, xip->xi_queue->eq_sgid);
541 541 }
542 542
543 543 /*
544 544 * Similar to the above function, but for use with readonly transport. Puts
545 545 * the event on the module's queue such that it's fmdo_recv function can pick
546 546 * it up and send it if appropriate.
547 547 */
548 548 static void
549 549 fmd_xprt_send_case_ro(fmd_case_t *cp, void *arg)
550 550 {
551 551 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
552 552 fmd_module_t *mp = arg;
553 553
554 554 fmd_event_t *e;
555 555 nvlist_t *nvl;
556 556 char *class;
557 557
558 558 if (cip->ci_state != FMD_CASE_SOLVED)
559 559 return;
560 560
561 561 nvl = fmd_case_mkevent(cp, FM_LIST_SUSPECT_CLASS);
562 562 (void) nvlist_lookup_string(nvl, FM_CLASS, &class);
563 563 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class);
564 564
565 565 fmd_dprintf(FMD_DBG_XPRT, "re-send %s for %s to rdonly transport %s\n",
566 566 FM_LIST_SUSPECT_CLASS, cip->ci_uuid, mp->mod_name);
567 567
568 568 fmd_dispq_dispatch_gid(fmd.d_disp, e, class, mp->mod_queue->eq_sgid);
569 569 }
570 570
571 571 void
572 572 fmd_xprt_event_run(fmd_xprt_impl_t *xip, nvlist_t *nvl)
573 573 {
574 574 if (!fmd_xprt_vmismatch(xip, nvl, NULL)) {
575 575 fmd_xprt_transition(xip, _fmd_xprt_state_run, "RUN");
576 576 fmd_case_hash_apply(fmd.d_cases, fmd_xprt_send_case, xip);
577 577 }
578 578 }
579 579
580 580 void
581 581 fmd_xprt_event_sub(fmd_xprt_impl_t *xip, nvlist_t *nvl)
582 582 {
583 583 char *class;
584 584
585 585 if (fmd_xprt_vmismatch(xip, nvl, NULL))
586 586 return; /* transitioned to error state */
587 587
588 588 if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_SUBCLASS, &class) != 0)
589 589 return; /* malformed protocol event */
590 590
591 591 (void) pthread_mutex_lock(&xip->xi_lock);
592 592 (void) fmd_xprt_class_hash_insert(xip, &xip->xi_lsub, class);
593 593 (void) pthread_mutex_unlock(&xip->xi_lock);
594 594
595 595 (void) pthread_mutex_lock(&xip->xi_stats_lock);
596 596 xip->xi_stats->xs_subscriptions.fmds_value.ui64++;
597 597 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
598 598 }
599 599
600 600 void
601 601 fmd_xprt_event_unsub(fmd_xprt_impl_t *xip, nvlist_t *nvl)
602 602 {
603 603 fmd_event_t *e;
604 604 char *class;
605 605
606 606 if (fmd_xprt_vmismatch(xip, nvl, NULL))
607 607 return; /* transitioned to error state */
608 608
609 609 if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_SUBCLASS, &class) != 0)
610 610 return; /* malformed protocol event */
611 611
612 612 (void) pthread_mutex_lock(&xip->xi_lock);
613 613 (void) fmd_xprt_class_hash_delete(xip, &xip->xi_lsub, class);
614 614 (void) pthread_mutex_unlock(&xip->xi_lock);
615 615
616 616 (void) pthread_mutex_lock(&xip->xi_stats_lock);
617 617 xip->xi_stats->xs_subscriptions.fmds_value.ui64--;
618 618 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
619 619
620 620 nvl = fmd_protocol_xprt_sub(xip->xi_queue->eq_mod,
621 621 "resource.fm.xprt.unsuback", xip->xi_version, class);
622 622
623 623 (void) nvlist_lookup_string(nvl, FM_CLASS, &class);
624 624 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class);
625 625 fmd_eventq_insert_at_time(xip->xi_queue, e);
626 626 }
627 627
628 628 void
629 629 fmd_xprt_event_unsuback(fmd_xprt_impl_t *xip, nvlist_t *nvl)
630 630 {
631 631 char *class;
632 632
633 633 if (fmd_xprt_vmismatch(xip, nvl, NULL))
634 634 return; /* transitioned to error state */
635 635
636 636 if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_SUBCLASS, &class) != 0)
637 637 return; /* malformed protocol event */
638 638
639 639 (void) pthread_mutex_lock(&xip->xi_lock);
640 640 (void) fmd_xprt_class_hash_delete(xip, &xip->xi_usub, class);
641 641 (void) pthread_mutex_unlock(&xip->xi_lock);
642 642 }
643 643
644 644 /*
645 645 * on diagnosing side, receive a uuclose from the proxy.
646 646 */
647 647 void
648 648 fmd_xprt_event_uuclose(fmd_xprt_impl_t *xip, nvlist_t *nvl)
649 649 {
650 650 fmd_case_t *cp;
651 651 char *uuid;
652 652
653 653 if (fmd_xprt_vmismatch(xip, nvl, NULL))
654 654 return; /* transitioned to error state */
655 655
656 656 if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_UUID, &uuid) == 0 &&
657 657 (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) {
658 658 /*
659 659 * update resource cache status and transition case
660 660 */
661 661 fmd_case_close_status(cp);
662 662 fmd_case_transition(cp, FMD_CASE_CLOSE_WAIT, FMD_CF_ISOLATED);
663 663 fmd_case_rele(cp);
664 664 }
665 665 }
666 666
667 667 /*
668 668 * on diagnosing side, receive a uuresolved from the proxy.
669 669 */
670 670 void
671 671 fmd_xprt_event_uuresolved(fmd_xprt_impl_t *xip, nvlist_t *nvl)
672 672 {
673 673 fmd_case_t *cp;
674 674 char *uuid;
675 675
676 676 if (fmd_xprt_vmismatch(xip, nvl, NULL))
677 677 return; /* transitioned to error state */
678 678
679 679 if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_UUID, &uuid) == 0 &&
680 680 (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) {
681 681 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
682 682
683 683 fmd_case_transition(cp, (cip->ci_state == FMD_CASE_REPAIRED) ?
684 684 FMD_CASE_RESOLVED : (cip->ci_state == FMD_CASE_CLOSED) ?
685 685 FMD_CASE_REPAIRED : FMD_CASE_CLOSE_WAIT, FMD_CF_RESOLVED);
686 686 fmd_case_rele(cp);
687 687 }
688 688 }
689 689
690 690 /*
691 691 * on diagnosing side, receive a repair/acquit from the proxy.
692 692 */
693 693 void
694 694 fmd_xprt_event_updated(fmd_xprt_impl_t *xip, nvlist_t *nvl)
695 695 {
696 696 fmd_case_t *cp;
697 697 char *uuid;
698 698
699 699 if (fmd_xprt_vmismatch(xip, nvl, NULL))
700 700 return; /* transitioned to error state */
701 701
702 702 if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_UUID, &uuid) == 0 &&
703 703 (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) {
704 704 uint8_t *statusp, *proxy_asrup = NULL;
705 705 uint_t nelem = 0;
706 706
707 707 /*
708 708 * Only update status with new repairs if "no remote repair"
709 709 * is not set. Do the case_update anyway though (as this will
710 710 * refresh the status on the proxy side).
711 711 */
712 712 if (!(xip->xi_flags & FMD_XPRT_NO_REMOTE_REPAIR)) {
713 713 if (nvlist_lookup_uint8_array(nvl,
714 714 FM_RSRC_XPRT_FAULT_STATUS, &statusp, &nelem) == 0 &&
715 715 nelem != 0) {
716 716 (void) nvlist_lookup_uint8_array(nvl,
717 717 FM_RSRC_XPRT_FAULT_HAS_ASRU, &proxy_asrup,
718 718 &nelem);
719 719 fmd_case_update_status(cp, statusp,
720 720 proxy_asrup, NULL);
721 721 }
722 722 fmd_case_update_containees(cp);
723 723 }
724 724 fmd_case_update(cp);
725 725 fmd_case_rele(cp);
726 726 }
727 727 }
728 728
729 729 void
730 730 fmd_xprt_event_error(fmd_xprt_impl_t *xip, nvlist_t *nvl)
731 731 {
732 732 char *class = "<unknown>";
733 733
734 734 (void) pthread_mutex_lock(&xip->xi_stats_lock);
735 735 xip->xi_stats->xs_discarded.fmds_value.ui64++;
736 736 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
737 737
738 738 (void) nvlist_lookup_string(nvl, FM_CLASS, &class);
739 739 TRACE((FMD_DBG_XPRT, "xprt %u bad event %s\n", xip->xi_id, class));
740 740
741 741 fmd_xprt_transition(xip, _fmd_xprt_state_err, "ERR");
742 742 }
743 743
744 744 void
745 745 fmd_xprt_event_drop(fmd_xprt_impl_t *xip, nvlist_t *nvl)
746 746 {
747 747 char *class = "<unknown>";
748 748
749 749 (void) pthread_mutex_lock(&xip->xi_stats_lock);
750 750 xip->xi_stats->xs_discarded.fmds_value.ui64++;
751 751 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
752 752
753 753 (void) nvlist_lookup_string(nvl, FM_CLASS, &class);
754 754 TRACE((FMD_DBG_XPRT, "xprt %u drop event %s\n", xip->xi_id, class));
755 755
756 756 }
757 757
758 758 fmd_xprt_t *
759 759 fmd_xprt_create(fmd_module_t *mp, uint_t flags, nvlist_t *auth, void *data)
760 760 {
761 761 fmd_xprt_impl_t *xip = fmd_zalloc(sizeof (fmd_xprt_impl_t), FMD_SLEEP);
762 762 fmd_stat_t *statv;
763 763 uint_t i, statc;
764 764
765 765 char buf[PATH_MAX];
766 766 fmd_event_t *e;
767 767 nvlist_t *nvl;
768 768 char *s;
769 769
770 770 (void) pthread_mutex_init(&xip->xi_lock, NULL);
771 771 (void) pthread_cond_init(&xip->xi_cv, NULL);
772 772 (void) pthread_mutex_init(&xip->xi_stats_lock, NULL);
773 773
774 774 xip->xi_auth = auth;
775 775 xip->xi_data = data;
776 776 xip->xi_version = FM_RSRC_XPRT_VERSION;
777 777 xip->xi_flags = flags;
778 778
779 779 /*
780 780 * Grab fmd.d_xprt_lock to block fmd_xprt_suspend_all() and then create
781 781 * a transport ID and make it visible in fmd.d_xprt_ids. If transports
782 782 * were previously suspended, set the FMD_XPRT_DSUSPENDED flag on us to
783 783 * ensure that this transport will not run until fmd_xprt_resume_all().
784 784 */
785 785 (void) pthread_mutex_lock(&fmd.d_xprt_lock);
786 786 xip->xi_id = fmd_idspace_alloc(fmd.d_xprt_ids, xip);
787 787
788 788 if (fmd.d_xprt_suspend != 0)
789 789 xip->xi_flags |= FMD_XPRT_DSUSPENDED;
790 790
791 791 (void) pthread_mutex_unlock(&fmd.d_xprt_lock);
792 792
793 793 /*
794 794 * If the module has not yet finished _fmd_init(), set the ISUSPENDED
795 795 * bit so that fmdo_send() is not called until _fmd_init() completes.
796 796 */
797 797 if (!(mp->mod_flags & FMD_MOD_INIT))
798 798 xip->xi_flags |= FMD_XPRT_ISUSPENDED;
799 799
800 800 /*
801 801 * Initialize the transport statistics that we keep on behalf of fmd.
802 802 * These are set up using a template defined at the top of this file.
803 803 * We rename each statistic with a prefix ensuring its uniqueness.
804 804 */
805 805 statc = sizeof (_fmd_xprt_stat_tmpl) / sizeof (fmd_stat_t);
806 806 statv = fmd_alloc(sizeof (_fmd_xprt_stat_tmpl), FMD_SLEEP);
807 807 bcopy(&_fmd_xprt_stat_tmpl, statv, sizeof (_fmd_xprt_stat_tmpl));
808 808
809 809 for (i = 0; i < statc; i++) {
810 810 (void) snprintf(statv[i].fmds_name,
811 811 sizeof (statv[i].fmds_name), "fmd.xprt.%u.%s", xip->xi_id,
812 812 ((fmd_stat_t *)&_fmd_xprt_stat_tmpl + i)->fmds_name);
813 813 }
814 814
815 815 xip->xi_stats = (fmd_xprt_stat_t *)fmd_ustat_insert(
816 816 mp->mod_ustat, FMD_USTAT_NOALLOC, statc, statv, NULL);
817 817
818 818 if (xip->xi_stats == NULL)
819 819 fmd_panic("failed to create xi_stats (%p)\n", (void *)statv);
820 820
821 821 xip->xi_stats->xs_module.fmds_value.str =
822 822 fmd_strdup(mp->mod_name, FMD_SLEEP);
823 823
824 824 if (xip->xi_auth != NULL)
825 825 fmd_xprt_authupdate(xip);
826 826
827 827 /*
828 828 * Create the outbound eventq for this transport and link to its stats.
829 829 * If any suspend bits were set above, suspend the eventq immediately.
830 830 */
831 831 xip->xi_queue = fmd_eventq_create(mp, &xip->xi_stats->xs_evqstat,
832 832 &xip->xi_stats_lock, mp->mod_stats->ms_xprtqlimit.fmds_value.ui32);
833 833
834 834 if (xip->xi_flags & FMD_XPRT_SMASK)
835 835 fmd_eventq_suspend(xip->xi_queue);
836 836
837 837 /*
838 838 * Create our subscription hashes: local subscriptions go to xi_queue,
839 839 * remote subscriptions are tracked only for protocol requests, and
840 840 * pending unsubscriptions are associated with the /dev/null eventq.
841 841 */
842 842 fmd_xprt_class_hash_create(&xip->xi_lsub, xip->xi_queue);
843 843 fmd_xprt_class_hash_create(&xip->xi_rsub, NULL);
844 844 fmd_xprt_class_hash_create(&xip->xi_usub, fmd.d_rmod->mod_queue);
845 845
846 846 /*
847 847 * Determine our initial state based upon the creation flags. If we're
848 848 * read-only, go directly to RUN. If we're accepting a new connection,
849 849 * wait for a SYN. Otherwise send a SYN and wait for an ACK.
850 850 */
851 851 if ((flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) {
852 852 /*
853 853 * Send the list.suspects across here for readonly transports.
854 854 * For read-write transport they will be sent on transition to
855 855 * RUN state in fmd_xprt_event_run().
856 856 */
857 857 fmd_case_hash_apply(fmd.d_cases, fmd_xprt_send_case_ro, mp);
858 858 fmd_xprt_transition(xip, _fmd_xprt_state_run, "RUN");
859 859 } else if (flags & FMD_XPRT_ACCEPT)
860 860 fmd_xprt_transition(xip, _fmd_xprt_state_syn, "SYN");
861 861 else
862 862 fmd_xprt_transition(xip, _fmd_xprt_state_ack, "ACK");
863 863
864 864 /*
865 865 * If client.xprtlog is set to TRUE, create a debugging log for the
866 866 * events received by the transport in var/fm/fmd/xprt/.
867 867 */
868 868 (void) fmd_conf_getprop(fmd.d_conf, "client.xprtlog", &i);
869 869 (void) fmd_conf_getprop(fmd.d_conf, "log.xprt", &s);
870 870
871 871 if (i) {
872 872 (void) snprintf(buf, sizeof (buf), "%s/%u.log", s, xip->xi_id);
873 873 xip->xi_log = fmd_log_open(fmd.d_rootdir, buf, FMD_LOG_XPRT);
874 874 }
875 875
876 876 ASSERT(fmd_module_locked(mp));
877 877 fmd_list_append(&mp->mod_transports, xip);
878 878
879 879 (void) pthread_mutex_lock(&mp->mod_stats_lock);
880 880 mp->mod_stats->ms_xprtopen.fmds_value.ui32++;
881 881 (void) pthread_mutex_unlock(&mp->mod_stats_lock);
882 882
883 883 /*
884 884 * If this is a read-only transport, return without creating a send
885 885 * queue thread and setting up any connection events in our queue.
886 886 */
887 887 if ((flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY)
888 888 goto out;
889 889
890 890 /*
891 891 * Once the transport is fully initialized, create a send queue thread
892 892 * and start any connect events flowing to complete our initialization.
893 893 */
894 894 if ((xip->xi_thread = fmd_thread_create(mp,
895 895 (fmd_thread_f *)fmd_xprt_send, xip)) == NULL) {
896 896
897 897 fmd_error(EFMD_XPRT_THR,
898 898 "failed to create thread for transport %u", xip->xi_id);
899 899
900 900 fmd_xprt_destroy((fmd_xprt_t *)xip);
901 901 (void) fmd_set_errno(EFMD_XPRT_THR);
902 902 return (NULL);
903 903 }
904 904
905 905 /*
906 906 * If the transport is not being opened to accept an inbound connect,
907 907 * start an outbound connection by enqueuing a SYN event for our peer.
908 908 */
909 909 if (!(flags & FMD_XPRT_ACCEPT)) {
910 910 nvl = fmd_protocol_xprt_ctl(mp,
911 911 "resource.fm.xprt.syn", FM_RSRC_XPRT_VERSION);
912 912
913 913 (void) nvlist_lookup_string(nvl, FM_CLASS, &s);
914 914 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s);
915 915 fmd_eventq_insert_at_time(xip->xi_queue, e);
916 916 }
917 917 out:
918 918 fmd_dprintf(FMD_DBG_XPRT, "opened transport %u\n", xip->xi_id);
919 919 return ((fmd_xprt_t *)xip);
920 920 }
921 921
922 922 void
923 923 fmd_xprt_destroy(fmd_xprt_t *xp)
924 924 {
925 925 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
926 926 fmd_module_t *mp = xip->xi_queue->eq_mod;
927 927 uint_t id = xip->xi_id;
928 928
929 929 fmd_case_impl_t *cip, *nip;
930 930 fmd_stat_t *sp;
931 931 uint_t i, n;
932 932
933 933 ASSERT(fmd_module_locked(mp));
934 934 fmd_list_delete(&mp->mod_transports, xip);
935 935
936 936 (void) pthread_mutex_lock(&mp->mod_stats_lock);
937 937 mp->mod_stats->ms_xprtopen.fmds_value.ui32--;
938 938 (void) pthread_mutex_unlock(&mp->mod_stats_lock);
939 939
940 940 (void) pthread_mutex_lock(&xip->xi_lock);
941 941
942 942 while (xip->xi_busy != 0)
943 943 (void) pthread_cond_wait(&xip->xi_cv, &xip->xi_lock);
944 944
945 945 /*
946 946 * Remove the transport from global visibility, cancel its send-side
947 947 * thread, join with it, and then remove the transport from module
948 948 * visibility. Once all this is done, destroy and free the transport.
949 949 */
950 950 (void) fmd_idspace_free(fmd.d_xprt_ids, xip->xi_id);
951 951
952 952 if (xip->xi_thread != NULL) {
953 953 fmd_eventq_abort(xip->xi_queue);
954 954 fmd_module_unlock(mp);
955 955 fmd_thread_destroy(xip->xi_thread, FMD_THREAD_JOIN);
956 956 fmd_module_lock(mp);
957 957 }
958 958
959 959 if (xip->xi_log != NULL)
960 960 fmd_log_rele(xip->xi_log);
961 961
962 962 /*
963 963 * Release every case handle in the module that was cached by this
964 964 * transport. This will result in these cases disappearing from the
965 965 * local case hash so that fmd_case_uuclose() and fmd_case_repaired()
966 966 * etc can no longer be used.
967 967 */
968 968 for (cip = fmd_list_next(&mp->mod_cases); cip != NULL; cip = nip) {
969 969 nip = fmd_list_next(cip);
970 970 if (cip->ci_xprt == xp)
971 971 fmd_case_discard((fmd_case_t *)cip, B_TRUE);
972 972 }
973 973
974 974 /*
975 975 * Destroy every class in the various subscription hashes and remove
976 976 * any corresponding subscriptions from the event dispatch queue.
977 977 */
978 978 fmd_xprt_class_hash_destroy(&xip->xi_lsub);
979 979 fmd_xprt_class_hash_destroy(&xip->xi_rsub);
980 980 fmd_xprt_class_hash_destroy(&xip->xi_usub);
981 981
982 982 /*
983 983 * Uniquify the stat names exactly as was done in fmd_xprt_create()
984 984 * before calling fmd_ustat_insert(), otherwise fmd_ustat_delete()
985 985 * won't find the entries in the hash table.
986 986 */
987 987 n = sizeof (_fmd_xprt_stat_tmpl) / sizeof (fmd_stat_t);
988 988 sp = fmd_alloc(sizeof (_fmd_xprt_stat_tmpl), FMD_SLEEP);
989 989 bcopy(&_fmd_xprt_stat_tmpl, sp, sizeof (_fmd_xprt_stat_tmpl));
990 990 for (i = 0; i < n; i++) {
991 991 (void) snprintf(sp[i].fmds_name,
992 992 sizeof (sp[i].fmds_name), "fmd.xprt.%u.%s", xip->xi_id,
993 993 ((fmd_stat_t *)&_fmd_xprt_stat_tmpl + i)->fmds_name);
994 994 }
995 995 fmd_ustat_delete(mp->mod_ustat, n, sp);
996 996 fmd_free(sp, sizeof (_fmd_xprt_stat_tmpl));
997 997
998 998 fmd_free(xip->xi_stats, sizeof (fmd_xprt_stat_t));
999 999 fmd_eventq_destroy(xip->xi_queue);
1000 1000 nvlist_free(xip->xi_auth);
1001 1001 fmd_free(xip, sizeof (fmd_xprt_impl_t));
1002 1002
1003 1003 fmd_dprintf(FMD_DBG_XPRT, "closed transport %u\n", id);
1004 1004 }
1005 1005
1006 1006 void
1007 1007 fmd_xprt_xsuspend(fmd_xprt_t *xp, uint_t flags)
1008 1008 {
1009 1009 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
1010 1010 uint_t oflags;
1011 1011
1012 1012 ASSERT((flags & ~FMD_XPRT_SMASK) == 0);
1013 1013 (void) pthread_mutex_lock(&xip->xi_lock);
1014 1014
1015 1015 oflags = xip->xi_flags;
1016 1016 xip->xi_flags |= flags;
1017 1017
1018 1018 if (!(oflags & FMD_XPRT_SMASK) && (xip->xi_flags & FMD_XPRT_SMASK) != 0)
1019 1019 fmd_eventq_suspend(xip->xi_queue);
1020 1020
1021 1021 (void) pthread_cond_broadcast(&xip->xi_cv);
1022 1022
1023 1023 while (xip->xi_busy != 0)
1024 1024 (void) pthread_cond_wait(&xip->xi_cv, &xip->xi_lock);
1025 1025
1026 1026 (void) pthread_mutex_unlock(&xip->xi_lock);
1027 1027 }
1028 1028
1029 1029 void
1030 1030 fmd_xprt_xresume(fmd_xprt_t *xp, uint_t flags)
1031 1031 {
1032 1032 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
1033 1033 uint_t oflags;
1034 1034
1035 1035 ASSERT((flags & ~FMD_XPRT_SMASK) == 0);
1036 1036 (void) pthread_mutex_lock(&xip->xi_lock);
1037 1037
1038 1038 oflags = xip->xi_flags;
1039 1039 xip->xi_flags &= ~flags;
1040 1040
1041 1041 if ((oflags & FMD_XPRT_SMASK) != 0 && !(xip->xi_flags & FMD_XPRT_SMASK))
1042 1042 fmd_eventq_resume(xip->xi_queue);
1043 1043
1044 1044 (void) pthread_cond_broadcast(&xip->xi_cv);
1045 1045 (void) pthread_mutex_unlock(&xip->xi_lock);
1046 1046 }
1047 1047
1048 1048 void
1049 1049 fmd_xprt_send(fmd_xprt_t *xp)
1050 1050 {
1051 1051 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
1052 1052 fmd_module_t *mp = xip->xi_queue->eq_mod;
1053 1053 fmd_event_t *ep;
1054 1054 int err;
1055 1055
1056 1056 while ((ep = fmd_eventq_delete(xip->xi_queue)) != NULL) {
1057 1057 if (FMD_EVENT_TTL(ep) == 0) {
1058 1058 fmd_event_rele(ep);
1059 1059 continue;
1060 1060 }
1061 1061
1062 1062 fmd_dprintf(FMD_DBG_XPRT, "xprt %u sending %s\n",
1063 1063 xip->xi_id, (char *)FMD_EVENT_DATA(ep));
1064 1064
1065 1065 err = mp->mod_ops->mop_transport(mp, xp, ep);
1066 1066 fmd_eventq_done(xip->xi_queue);
1067 1067
1068 1068 if (err == FMD_SEND_RETRY) {
1069 1069 fmd_eventq_insert_at_time(xip->xi_queue, ep);
1070 1070 (void) pthread_mutex_lock(&xip->xi_stats_lock);
1071 1071 xip->xi_stats->xs_retried.fmds_value.ui64++;
1072 1072 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
1073 1073 }
1074 1074
1075 1075 if (err != FMD_SEND_SUCCESS && err != FMD_SEND_RETRY) {
1076 1076 (void) pthread_mutex_lock(&xip->xi_stats_lock);
1077 1077 xip->xi_stats->xs_lost.fmds_value.ui64++;
1078 1078 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
1079 1079 }
1080 1080
1081 1081 fmd_event_rele(ep);
1082 1082 }
1083 1083 }
1084 1084
1085 1085 /*
1086 1086 * This function creates a local suspect list. This is used when a suspect list
1087 1087 * is created directly by an external source like fminject.
1088 1088 */
1089 1089 static void
1090 1090 fmd_xprt_list_suspect_local(fmd_xprt_t *xp, nvlist_t *nvl)
1091 1091 {
1092 1092 nvlist_t **nvlp;
1093 1093 nvlist_t *de_fmri, *de_fmri_dup = NULL;
1094 1094 int64_t *diag_time;
1095 1095 char *code = NULL;
1096 1096 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
1097 1097 fmd_case_t *cp;
1098 1098 uint_t nelem = 0, nelem2 = 0, i;
1099 1099 boolean_t injected;
1100 1100
1101 1101 fmd_module_lock(xip->xi_queue->eq_mod);
1102 1102 cp = fmd_case_create(xip->xi_queue->eq_mod, NULL, NULL);
1103 1103 if (cp == NULL) {
1104 1104 fmd_module_unlock(xip->xi_queue->eq_mod);
1105 1105 return;
1106 1106 }
1107 1107
1108 1108 /*
1109 1109 * copy diag_code if present
1110 1110 */
1111 1111 (void) nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &code);
1112 1112 if (code != NULL) {
1113 1113 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
1114 1114
1115 1115 cip->ci_precanned = 1;
1116 1116 fmd_case_setcode(cp, code);
1117 1117 }
1118 1118
1119 1119 /*
1120 1120 * copy suspects
1121 1121 */
1122 1122 (void) nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST, &nvlp,
1123 1123 &nelem);
1124 1124 for (i = 0; i < nelem; i++) {
1125 1125 nvlist_t *flt_copy, *asru = NULL, *fru = NULL, *rsrc = NULL;
1126 1126 topo_hdl_t *thp;
1127 1127 char *loc = NULL;
1128 1128 int err;
1129 1129
1130 1130 thp = fmd_fmri_topo_hold(TOPO_VERSION);
1131 1131 (void) nvlist_xdup(nvlp[i], &flt_copy, &fmd.d_nva);
1132 1132 (void) nvlist_lookup_nvlist(nvlp[i], FM_FAULT_RESOURCE, &rsrc);
1133 1133
1134 1134 /*
1135 1135 * If no fru specified, get it from topo
1136 1136 */
1137 1137 if (nvlist_lookup_nvlist(nvlp[i], FM_FAULT_FRU, &fru) != 0 &&
1138 1138 rsrc && topo_fmri_fru(thp, rsrc, &fru, &err) == 0)
1139 1139 (void) nvlist_add_nvlist(flt_copy, FM_FAULT_FRU, fru);
1140 1140 /*
1141 1141 * If no asru specified, get it from topo
1142 1142 */
1143 1143 if (nvlist_lookup_nvlist(nvlp[i], FM_FAULT_ASRU, &asru) != 0 &&
1144 1144 rsrc && topo_fmri_asru(thp, rsrc, &asru, &err) == 0)
1145 1145 (void) nvlist_add_nvlist(flt_copy, FM_FAULT_ASRU, asru);
1146 1146 /*
1147 1147 * If no location specified, get it from topo
1148 1148 */
1149 1149 if (nvlist_lookup_string(nvlp[i], FM_FAULT_LOCATION,
1150 1150 &loc) != 0) {
↓ open down ↓ |
1150 lines elided |
↑ open up ↑ |
1151 1151 if (fru && topo_fmri_label(thp, fru, &loc, &err) == 0)
1152 1152 (void) nvlist_add_string(flt_copy,
1153 1153 FM_FAULT_LOCATION, loc);
1154 1154 else if (rsrc && topo_fmri_label(thp, rsrc, &loc,
1155 1155 &err) == 0)
1156 1156 (void) nvlist_add_string(flt_copy,
1157 1157 FM_FAULT_LOCATION, loc);
1158 1158 if (loc)
1159 1159 topo_hdl_strfree(thp, loc);
1160 1160 }
1161 - if (fru)
1162 - nvlist_free(fru);
1163 - if (asru)
1164 - nvlist_free(asru);
1165 - if (rsrc)
1166 - nvlist_free(rsrc);
1161 + nvlist_free(fru);
1162 + nvlist_free(asru);
1163 + nvlist_free(rsrc);
1167 1164 fmd_fmri_topo_rele(thp);
1168 1165 fmd_case_insert_suspect(cp, flt_copy);
1169 1166 }
1170 1167
1171 1168 /*
1172 1169 * copy diag_time if present
1173 1170 */
1174 1171 if (nvlist_lookup_int64_array(nvl, FM_SUSPECT_DIAG_TIME, &diag_time,
1175 1172 &nelem2) == 0 && nelem2 >= 2)
1176 1173 fmd_case_settime(cp, diag_time[0], diag_time[1]);
1177 1174
1178 1175 /*
1179 1176 * copy DE fmri if present
1180 1177 */
1181 1178 if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &de_fmri) == 0) {
1182 1179 (void) nvlist_xdup(de_fmri, &de_fmri_dup, &fmd.d_nva);
1183 1180 fmd_case_set_de_fmri(cp, de_fmri_dup);
1184 1181 }
1185 1182
1186 1183 /*
1187 1184 * copy injected if present
1188 1185 */
1189 1186 if (nvlist_lookup_boolean_value(nvl, FM_SUSPECT_INJECTED,
1190 1187 &injected) == 0 && injected)
1191 1188 fmd_case_set_injected(cp);
1192 1189
1193 1190 fmd_case_transition(cp, FMD_CASE_SOLVED, FMD_CF_SOLVED);
1194 1191 fmd_module_unlock(xip->xi_queue->eq_mod);
1195 1192 }
1196 1193
1197 1194 /*
1198 1195 * This function is called to create a proxy case on receipt of a list.suspect
1199 1196 * from the diagnosing side of the transport.
1200 1197 */
1201 1198 static void
1202 1199 fmd_xprt_list_suspect(fmd_xprt_t *xp, nvlist_t *nvl)
1203 1200 {
1204 1201 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
1205 1202 nvlist_t **nvlp;
1206 1203 uint_t nelem = 0, nelem2 = 0, i;
1207 1204 int64_t *diag_time;
1208 1205 topo_hdl_t *thp;
1209 1206 char *class;
1210 1207 nvlist_t *rsrc, *asru, *de_fmri, *de_fmri_dup = NULL;
1211 1208 nvlist_t *flt_copy;
1212 1209 int err;
1213 1210 nvlist_t **asrua;
1214 1211 uint8_t *proxy_asru = NULL;
1215 1212 int got_proxy_asru = 0;
1216 1213 int got_hc_rsrc = 0;
1217 1214 int got_hc_asru = 0;
1218 1215 int got_present_rsrc = 0;
1219 1216 uint8_t *diag_asru = NULL;
1220 1217 char *scheme;
1221 1218 uint8_t *statusp;
1222 1219 char *uuid, *code;
1223 1220 fmd_case_t *cp;
1224 1221 fmd_case_impl_t *cip;
1225 1222 int need_update = 0;
1226 1223 boolean_t injected;
1227 1224
1228 1225 if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) != 0)
1229 1226 return;
1230 1227 if (nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &code) != 0)
1231 1228 return;
1232 1229 (void) nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST, &nvlp,
1233 1230 &nelem);
1234 1231
1235 1232 /*
1236 1233 * In order to implement FMD_XPRT_HCONLY and FMD_XPRT_HC_PRESENT_ONLY
1237 1234 * etc we first scan the suspects to see if
1238 1235 * - there was an asru in the received fault
1239 1236 * - there was an hc-scheme resource in the received fault
1240 1237 * - any hc-scheme resource in the received fault is present in the
1241 1238 * local topology
1242 1239 * - any hc-scheme resource in the received fault has an asru in the
1243 1240 * local topology
1244 1241 */
1245 1242 if (nelem > 0) {
1246 1243 asrua = fmd_zalloc(sizeof (nvlist_t *) * nelem, FMD_SLEEP);
1247 1244 proxy_asru = fmd_zalloc(sizeof (uint8_t) * nelem, FMD_SLEEP);
1248 1245 diag_asru = fmd_zalloc(sizeof (uint8_t) * nelem, FMD_SLEEP);
1249 1246 thp = fmd_fmri_topo_hold(TOPO_VERSION);
1250 1247 for (i = 0; i < nelem; i++) {
1251 1248 if (nvlist_lookup_nvlist(nvlp[i], FM_FAULT_ASRU,
1252 1249 &asru) == 0 && asru != NULL)
1253 1250 diag_asru[i] = 1;
1254 1251 if (nvlist_lookup_string(nvlp[i], FM_CLASS,
1255 1252 &class) != 0 || strncmp(class, "fault", 5) != 0)
1256 1253 continue;
1257 1254 /*
1258 1255 * If there is an hc-scheme asru, use that to find the
1259 1256 * real asru. Otherwise if there is an hc-scheme
1260 1257 * resource, work out the old asru from that.
1261 1258 * This order is to allow a two stage evaluation
1262 1259 * of the asru where a fault in the diagnosing side
1263 1260 * is in a component not visible to the proxy side,
1264 1261 * but prevents a component that is visible from
1265 1262 * working. So the diagnosing side sets the asru to
1266 1263 * the latter component (in hc-scheme as the diagnosing
1267 1264 * side doesn't know about the proxy side's virtual
1268 1265 * schemes), and then the proxy side can convert that
1269 1266 * to a suitable virtual scheme asru.
1270 1267 */
1271 1268 if (nvlist_lookup_nvlist(nvlp[i], FM_FAULT_ASRU,
1272 1269 &asru) == 0 && asru != NULL &&
1273 1270 nvlist_lookup_string(asru, FM_FMRI_SCHEME,
1274 1271 &scheme) == 0 &&
1275 1272 strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
1276 1273 got_hc_asru = 1;
1277 1274 if (xip->xi_flags & FMD_XPRT_EXTERNAL)
1278 1275 continue;
1279 1276 if (topo_fmri_present(thp, asru, &err) != 0)
1280 1277 got_present_rsrc = 1;
1281 1278 if (topo_fmri_asru(thp, asru, &asrua[i],
1282 1279 &err) == 0) {
1283 1280 proxy_asru[i] =
1284 1281 FMD_PROXY_ASRU_FROM_ASRU;
1285 1282 got_proxy_asru = 1;
1286 1283 }
1287 1284 } else if (nvlist_lookup_nvlist(nvlp[i],
1288 1285 FM_FAULT_RESOURCE, &rsrc) == 0 && rsrc != NULL &&
1289 1286 nvlist_lookup_string(rsrc, FM_FMRI_SCHEME,
1290 1287 &scheme) == 0 &&
1291 1288 strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) {
1292 1289 got_hc_rsrc = 1;
1293 1290 if (xip->xi_flags & FMD_XPRT_EXTERNAL)
1294 1291 continue;
1295 1292 if (topo_fmri_present(thp, rsrc, &err) != 0)
1296 1293 got_present_rsrc = 1;
1297 1294 if (topo_fmri_asru(thp, rsrc, &asrua[i],
1298 1295 &err) == 0) {
1299 1296 proxy_asru[i] =
1300 1297 FMD_PROXY_ASRU_FROM_RSRC;
1301 1298 got_proxy_asru = 1;
1302 1299 }
1303 1300 }
1304 1301 }
1305 1302 fmd_fmri_topo_rele(thp);
1306 1303 }
1307 1304
1308 1305 /*
1309 1306 * If we're set up only to report hc-scheme faults, and
1310 1307 * there aren't any, then just drop the event.
1311 1308 */
1312 1309 if (got_hc_rsrc == 0 && got_hc_asru == 0 &&
1313 1310 (xip->xi_flags & FMD_XPRT_HCONLY)) {
1314 1311 if (nelem > 0) {
1315 1312 fmd_free(proxy_asru, sizeof (uint8_t) * nelem);
1316 1313 fmd_free(diag_asru, sizeof (uint8_t) * nelem);
1317 1314 fmd_free(asrua, sizeof (nvlist_t *) * nelem);
1318 1315 }
1319 1316 return;
↓ open down ↓ |
143 lines elided |
↑ open up ↑ |
1320 1317 }
1321 1318
1322 1319 /*
1323 1320 * If we're set up only to report locally present hc-scheme
1324 1321 * faults, and there aren't any, then just drop the event.
1325 1322 */
1326 1323 if (got_present_rsrc == 0 &&
1327 1324 (xip->xi_flags & FMD_XPRT_HC_PRESENT_ONLY)) {
1328 1325 if (nelem > 0) {
1329 1326 for (i = 0; i < nelem; i++)
1330 - if (asrua[i])
1331 - nvlist_free(asrua[i]);
1327 + nvlist_free(asrua[i]);
1332 1328 fmd_free(proxy_asru, sizeof (uint8_t) * nelem);
1333 1329 fmd_free(diag_asru, sizeof (uint8_t) * nelem);
1334 1330 fmd_free(asrua, sizeof (nvlist_t *) * nelem);
1335 1331 }
1336 1332 return;
1337 1333 }
1338 1334
1339 1335 /*
1340 1336 * If fmd_case_recreate() returns NULL, UUID is already known.
1341 1337 */
1342 1338 fmd_module_lock(xip->xi_queue->eq_mod);
1343 1339 if ((cp = fmd_case_recreate(xip->xi_queue->eq_mod, xp,
1344 1340 FMD_CASE_UNSOLVED, uuid, code)) == NULL) {
1345 1341 if (nelem > 0) {
1346 1342 for (i = 0; i < nelem; i++)
1347 - if (asrua[i])
1348 - nvlist_free(asrua[i]);
1343 + nvlist_free(asrua[i]);
1349 1344 fmd_free(proxy_asru, sizeof (uint8_t) * nelem);
1350 1345 fmd_free(diag_asru, sizeof (uint8_t) * nelem);
1351 1346 fmd_free(asrua, sizeof (nvlist_t *) * nelem);
1352 1347 }
1353 1348 fmd_module_unlock(xip->xi_queue->eq_mod);
1354 1349 return;
1355 1350 }
1356 1351
1357 1352 cip = (fmd_case_impl_t *)cp;
1358 1353 cip->ci_diag_asru = diag_asru;
1359 1354 cip->ci_proxy_asru = proxy_asru;
1360 1355 for (i = 0; i < nelem; i++) {
1361 1356 (void) nvlist_xdup(nvlp[i], &flt_copy, &fmd.d_nva);
1362 1357 if (proxy_asru[i] != FMD_PROXY_ASRU_NOT_NEEDED) {
1363 1358 /*
1364 1359 * Copy suspects, but remove/replace asru first. Also if
1365 1360 * the original asru was hc-scheme use that as resource.
1366 1361 */
1367 1362 if (proxy_asru[i] == FMD_PROXY_ASRU_FROM_ASRU) {
1368 1363 (void) nvlist_remove(flt_copy,
1369 1364 FM_FAULT_RESOURCE, DATA_TYPE_NVLIST);
1370 1365 (void) nvlist_lookup_nvlist(flt_copy,
1371 1366 FM_FAULT_ASRU, &asru);
1372 1367 (void) nvlist_add_nvlist(flt_copy,
1373 1368 FM_FAULT_RESOURCE, asru);
1374 1369 }
1375 1370 (void) nvlist_remove(flt_copy, FM_FAULT_ASRU,
1376 1371 DATA_TYPE_NVLIST);
1377 1372 (void) nvlist_add_nvlist(flt_copy, FM_FAULT_ASRU,
1378 1373 asrua[i]);
1379 1374 nvlist_free(asrua[i]);
1380 1375 } else if (got_hc_asru == 0 &&
1381 1376 nvlist_lookup_nvlist(flt_copy, FM_FAULT_ASRU,
1382 1377 &asru) == 0 && asru != NULL) {
1383 1378 /*
1384 1379 * If we have an asru from diag side, but it's not
1385 1380 * in hc scheme, then we can't be sure what it
1386 1381 * represents, so mark as no retire.
1387 1382 */
1388 1383 (void) nvlist_add_boolean_value(flt_copy,
1389 1384 FM_SUSPECT_RETIRE, B_FALSE);
1390 1385 }
1391 1386 fmd_case_insert_suspect(cp, flt_copy);
1392 1387 }
1393 1388 /*
1394 1389 * copy diag_time
1395 1390 */
1396 1391 if (nvlist_lookup_int64_array(nvl, FM_SUSPECT_DIAG_TIME, &diag_time,
1397 1392 &nelem2) == 0 && nelem2 >= 2)
1398 1393 fmd_case_settime(cp, diag_time[0], diag_time[1]);
1399 1394 /*
1400 1395 * copy DE fmri
1401 1396 */
1402 1397 if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &de_fmri) == 0) {
1403 1398 (void) nvlist_xdup(de_fmri, &de_fmri_dup, &fmd.d_nva);
1404 1399 fmd_case_set_de_fmri(cp, de_fmri_dup);
1405 1400 }
1406 1401
1407 1402 /*
1408 1403 * copy injected if present
1409 1404 */
1410 1405 if (nvlist_lookup_boolean_value(nvl, FM_SUSPECT_INJECTED,
1411 1406 &injected) == 0 && injected)
1412 1407 fmd_case_set_injected(cp);
1413 1408
1414 1409 /*
1415 1410 * Transition to solved. This will log the suspect list and create
1416 1411 * the resource cache entries.
1417 1412 */
1418 1413 fmd_case_transition(cp, FMD_CASE_SOLVED, FMD_CF_SOLVED);
1419 1414
1420 1415 /*
1421 1416 * Update status if it is not simply "all faulty" (can happen if
1422 1417 * list.suspects are being re-sent when the transport has reconnected).
1423 1418 */
1424 1419 (void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS, &statusp,
1425 1420 &nelem);
1426 1421 for (i = 0; i < nelem; i++) {
1427 1422 if ((statusp[i] & (FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE |
1428 1423 FM_SUSPECT_NOT_PRESENT | FM_SUSPECT_DEGRADED)) !=
1429 1424 FM_SUSPECT_FAULTY)
1430 1425 need_update = 1;
1431 1426 }
1432 1427 if (need_update) {
1433 1428 fmd_case_update_status(cp, statusp, cip->ci_proxy_asru,
1434 1429 cip->ci_diag_asru);
1435 1430 fmd_case_update_containees(cp);
1436 1431 fmd_case_update(cp);
1437 1432 }
1438 1433
1439 1434 /*
1440 1435 * if asru on proxy side, send an update back to the diagnosing side to
1441 1436 * update UNUSABLE/DEGRADED.
1442 1437 */
1443 1438 if (got_proxy_asru)
1444 1439 fmd_case_xprt_updated(cp);
1445 1440
1446 1441 if (nelem > 0)
1447 1442 fmd_free(asrua, sizeof (nvlist_t *) * nelem);
1448 1443 fmd_module_unlock(xip->xi_queue->eq_mod);
1449 1444 }
1450 1445
1451 1446 void
1452 1447 fmd_xprt_recv(fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt, boolean_t logonly)
1453 1448 {
1454 1449 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
1455 1450 const fmd_xprt_rule_t *xrp;
1456 1451 fmd_t *dp = &fmd;
1457 1452
1458 1453 fmd_event_t *e;
1459 1454 char *class, *uuid;
1460 1455 boolean_t isproto, isereport, isireport, ishvireport, issysevent;
1461 1456
1462 1457 uint64_t *tod;
1463 1458 uint8_t ttl;
1464 1459 uint_t n;
1465 1460 fmd_case_t *cp;
1466 1461
1467 1462 /*
1468 1463 * Grab the transport lock and set the busy flag to indicate we are
1469 1464 * busy receiving an event. If [DI]SUSPEND is pending, wait until fmd
1470 1465 * resumes the transport before continuing on with the receive.
1471 1466 */
1472 1467 (void) pthread_mutex_lock(&xip->xi_lock);
1473 1468
1474 1469 while (xip->xi_flags & (FMD_XPRT_DSUSPENDED | FMD_XPRT_ISUSPENDED)) {
1475 1470
1476 1471 if (fmd.d_signal != 0) {
1477 1472 (void) pthread_mutex_unlock(&xip->xi_lock);
1478 1473 return; /* fmd_destroy() is in progress */
1479 1474 }
1480 1475
1481 1476 (void) pthread_cond_wait(&xip->xi_cv, &xip->xi_lock);
1482 1477 }
1483 1478
1484 1479 xip->xi_busy++;
1485 1480 ASSERT(xip->xi_busy != 0);
1486 1481
1487 1482 (void) pthread_mutex_unlock(&xip->xi_lock);
1488 1483
1489 1484 (void) pthread_mutex_lock(&xip->xi_stats_lock);
1490 1485 xip->xi_stats->xs_received.fmds_value.ui64++;
1491 1486 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
1492 1487
1493 1488 if (nvlist_lookup_string(nvl, FM_CLASS, &class) != 0) {
1494 1489 fmd_error(EFMD_XPRT_PAYLOAD, "discarding nvlist %p: missing "
1495 1490 "required \"%s\" payload element", (void *)nvl, FM_CLASS);
1496 1491
1497 1492 (void) pthread_mutex_lock(&xip->xi_stats_lock);
1498 1493 xip->xi_stats->xs_discarded.fmds_value.ui64++;
1499 1494 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
1500 1495
1501 1496 nvlist_free(nvl);
1502 1497 goto done;
1503 1498 }
1504 1499
1505 1500 fmd_dprintf(FMD_DBG_XPRT, "xprt %u %s %s\n", xip->xi_id,
1506 1501 ((logonly == FMD_B_TRUE) ? "logging" : "posting"), class);
1507 1502
1508 1503 isereport = (strncmp(class, FM_EREPORT_CLASS ".",
1509 1504 sizeof (FM_EREPORT_CLASS)) == 0) ? FMD_B_TRUE : FMD_B_FALSE;
1510 1505
1511 1506 isireport = (strncmp(class, FM_IREPORT_CLASS ".",
1512 1507 sizeof (FM_IREPORT_CLASS)) == 0) ? FMD_B_TRUE : FMD_B_FALSE;
1513 1508
1514 1509 issysevent = (strncmp(class, SYSEVENT_RSRC_CLASS,
1515 1510 sizeof (SYSEVENT_RSRC_CLASS) - 1)) == 0 ? FMD_B_TRUE : FMD_B_FALSE;
1516 1511
1517 1512 if (isireport) {
1518 1513 char *pri;
1519 1514
1520 1515 if (nvlist_lookup_string(nvl, FM_IREPORT_PRIORITY, &pri) == 0 &&
1521 1516 strncmp(pri, "high", 5) == 0) {
1522 1517 ishvireport = 1;
1523 1518 } else {
1524 1519 ishvireport = 0;
1525 1520 }
1526 1521 }
1527 1522
1528 1523 /*
1529 1524 * The logonly flag should only be set for ereports.
1530 1525 */
1531 1526 if (logonly == FMD_B_TRUE && isereport == FMD_B_FALSE) {
1532 1527 fmd_error(EFMD_XPRT_INVAL, "discarding nvlist %p: "
1533 1528 "logonly flag is not valid for class %s",
1534 1529 (void *)nvl, class);
1535 1530
1536 1531 (void) pthread_mutex_lock(&xip->xi_stats_lock);
1537 1532 xip->xi_stats->xs_discarded.fmds_value.ui64++;
1538 1533 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
1539 1534
1540 1535 nvlist_free(nvl);
1541 1536 goto done;
1542 1537 }
1543 1538
1544 1539 /*
1545 1540 * If a time-to-live value is present in the event and is zero, drop
1546 1541 * the event and bump xs_timeouts. Otherwise decrement the TTL value.
1547 1542 */
1548 1543 if (nvlist_lookup_uint8(nvl, FMD_EVN_TTL, &ttl) == 0) {
1549 1544 if (ttl == 0) {
1550 1545 fmd_dprintf(FMD_DBG_XPRT, "xprt %u nvlist %p (%s) "
1551 1546 "timeout: event received with ttl=0\n",
1552 1547 xip->xi_id, (void *)nvl, class);
1553 1548
1554 1549 (void) pthread_mutex_lock(&xip->xi_stats_lock);
1555 1550 xip->xi_stats->xs_timeouts.fmds_value.ui64++;
1556 1551 (void) pthread_mutex_unlock(&xip->xi_stats_lock);
1557 1552
1558 1553 nvlist_free(nvl);
1559 1554 goto done;
1560 1555 }
1561 1556 (void) nvlist_remove(nvl, FMD_EVN_TTL, DATA_TYPE_UINT8);
1562 1557 (void) nvlist_add_uint8(nvl, FMD_EVN_TTL, ttl - 1);
1563 1558 }
1564 1559
1565 1560 /*
1566 1561 * If we are using the native system clock, the underlying transport
1567 1562 * code can provide a tighter event time bound by telling us when the
1568 1563 * event was enqueued. If we're using simulated clocks, this time
1569 1564 * has no meaning to us, so just reset the value to use HRT_NOW.
1570 1565 */
1571 1566 if (dp->d_clockops != &fmd_timeops_native)
1572 1567 hrt = FMD_HRT_NOW;
1573 1568
1574 1569 /*
1575 1570 * If an event's class is in the FMD_CTL_CLASS family, then create a
1576 1571 * control event. If a FMD_EVN_TOD member is found, create a protocol
1577 1572 * event using this time. Otherwise create a protocol event using hrt.
1578 1573 */
1579 1574 isproto = (strncmp(class, FMD_CTL_CLASS, FMD_CTL_CLASS_LEN) == 0) ?
1580 1575 FMD_B_FALSE : FMD_B_TRUE;
1581 1576 if (isproto == FMD_B_FALSE)
1582 1577 e = fmd_event_create(FMD_EVT_CTL, hrt, nvl, fmd_ctl_init(nvl));
1583 1578 else if (nvlist_lookup_uint64_array(nvl, FMD_EVN_TOD, &tod, &n) != 0)
1584 1579 e = fmd_event_create(FMD_EVT_PROTOCOL, hrt, nvl, class);
1585 1580 else {
1586 1581 e = fmd_event_recreate(FMD_EVT_PROTOCOL,
1587 1582 NULL, nvl, class, NULL, 0, 0);
1588 1583 }
1589 1584
1590 1585 /*
1591 1586 * If the debug log is enabled, create a temporary event, log it to the
1592 1587 * debug log, and then reset the underlying state of the event.
1593 1588 */
1594 1589 if (xip->xi_log != NULL) {
1595 1590 fmd_event_impl_t *ep = (fmd_event_impl_t *)e;
1596 1591
1597 1592 fmd_log_append(xip->xi_log, e, NULL);
1598 1593
1599 1594 ep->ev_flags |= FMD_EVF_VOLATILE;
1600 1595 ep->ev_off = 0;
1601 1596 ep->ev_len = 0;
1602 1597
1603 1598 if (ep->ev_log != NULL) {
1604 1599 fmd_log_rele(ep->ev_log);
1605 1600 ep->ev_log = NULL;
1606 1601 }
1607 1602 }
1608 1603
1609 1604 /*
1610 1605 * Iterate over the rules for the current state trying to match the
1611 1606 * event class to one of our special rules. If a rule is matched, the
1612 1607 * event is consumed and not dispatched to other modules. If the rule
1613 1608 * set ends without matching an event, we fall through to dispatching.
1614 1609 */
1615 1610 for (xrp = xip->xi_state; xrp->xr_class != NULL; xrp++) {
1616 1611 if (fmd_event_match(e, FMD_EVT_PROTOCOL, xrp->xr_class)) {
1617 1612 fmd_event_hold(e);
1618 1613 xrp->xr_func(xip, nvl);
1619 1614 fmd_event_rele(e);
1620 1615 goto done;
1621 1616 }
1622 1617 }
1623 1618
1624 1619 /*
1625 1620 * Record ereports and ireports in the log. This code will
1626 1621 * be replaced later with a per-transport intent log instead.
1627 1622 */
1628 1623 if (isereport == FMD_B_TRUE || isireport == FMD_B_TRUE ||
1629 1624 issysevent == B_TRUE) {
1630 1625 pthread_rwlock_t *lockp;
1631 1626 fmd_log_t *lp;
1632 1627
1633 1628 if (isereport == FMD_B_TRUE) {
1634 1629 lp = fmd.d_errlog;
1635 1630 lockp = &fmd.d_log_lock;
1636 1631 } else {
1637 1632 if (ishvireport || issysevent) {
1638 1633 lp = fmd.d_hvilog;
1639 1634 lockp = &fmd.d_hvilog_lock;
1640 1635 } else {
1641 1636 lp = fmd.d_ilog;
1642 1637 lockp = &fmd.d_ilog_lock;
1643 1638 }
1644 1639 }
1645 1640
1646 1641 (void) pthread_rwlock_rdlock(lockp);
1647 1642 fmd_log_append(lp, e, NULL);
1648 1643 (void) pthread_rwlock_unlock(lockp);
1649 1644 }
1650 1645
1651 1646 /*
1652 1647 * If a list.suspect event is received, create a case for the specified
1653 1648 * UUID in the case hash, with the transport module as its owner.
1654 1649 */
1655 1650 if (fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_SUSPECT_CLASS)) {
1656 1651 if (xip->xi_flags & FMD_XPRT_CACHE_AS_LOCAL)
1657 1652 fmd_xprt_list_suspect_local(xp, nvl);
1658 1653 else
1659 1654 fmd_xprt_list_suspect(xp, nvl);
1660 1655 fmd_event_hold(e);
1661 1656 fmd_event_rele(e);
1662 1657 goto done;
1663 1658 }
1664 1659
1665 1660 /*
1666 1661 * If a list.updated or list.repaired event is received, update the
1667 1662 * resource cache status and the local case.
1668 1663 */
1669 1664 if (fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_REPAIRED_CLASS) ||
1670 1665 fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_UPDATED_CLASS)) {
1671 1666 uint8_t *statusp;
1672 1667 uint_t nelem = 0;
1673 1668
1674 1669 (void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS,
1675 1670 &statusp, &nelem);
1676 1671 fmd_module_lock(xip->xi_queue->eq_mod);
1677 1672 if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) == 0 &&
1678 1673 (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) {
1679 1674 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
1680 1675 if (cip->ci_xprt != NULL) {
1681 1676 fmd_case_update_status(cp, statusp,
1682 1677 cip->ci_proxy_asru, cip->ci_diag_asru);
1683 1678 fmd_case_update_containees(cp);
1684 1679 fmd_case_update(cp);
1685 1680 }
1686 1681 fmd_case_rele(cp);
1687 1682 }
1688 1683 fmd_module_unlock(xip->xi_queue->eq_mod);
1689 1684 fmd_event_hold(e);
1690 1685 fmd_event_rele(e);
1691 1686 goto done;
1692 1687 }
1693 1688
1694 1689 /*
1695 1690 * If a list.isolated event is received, update resource cache status
1696 1691 */
1697 1692 if (fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_ISOLATED_CLASS)) {
1698 1693 uint8_t *statusp;
1699 1694 uint_t nelem = 0;
1700 1695
1701 1696 (void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS,
1702 1697 &statusp, &nelem);
1703 1698 fmd_module_lock(xip->xi_queue->eq_mod);
1704 1699 if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) == 0 &&
1705 1700 (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) {
1706 1701 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
1707 1702 if (cip->ci_xprt != NULL)
1708 1703 fmd_case_update_status(cp, statusp,
1709 1704 cip->ci_proxy_asru, cip->ci_diag_asru);
1710 1705 fmd_case_rele(cp);
1711 1706 }
1712 1707 fmd_module_unlock(xip->xi_queue->eq_mod);
1713 1708 fmd_event_hold(e);
1714 1709 fmd_event_rele(e);
1715 1710 goto done;
1716 1711 }
1717 1712
1718 1713 /*
1719 1714 * If a list.resolved event is received, resolve the local case.
1720 1715 */
1721 1716 if (fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_RESOLVED_CLASS)) {
1722 1717 fmd_module_lock(xip->xi_queue->eq_mod);
1723 1718 if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) == 0 &&
1724 1719 (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) {
1725 1720 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
1726 1721 if (cip->ci_xprt != NULL)
1727 1722 fmd_case_transition(cp, (cip->ci_state ==
1728 1723 FMD_CASE_REPAIRED) ? FMD_CASE_RESOLVED :
1729 1724 (cip->ci_state == FMD_CASE_CLOSED) ?
1730 1725 FMD_CASE_REPAIRED : FMD_CASE_CLOSE_WAIT,
1731 1726 FMD_CF_RESOLVED);
1732 1727 fmd_case_rele(cp);
1733 1728 }
1734 1729 fmd_module_unlock(xip->xi_queue->eq_mod);
1735 1730 fmd_event_hold(e);
1736 1731 fmd_event_rele(e);
1737 1732 goto done;
1738 1733 }
1739 1734
1740 1735 if (logonly == FMD_B_TRUE || (xip->xi_flags & FMD_XPRT_EXTERNAL)) {
1741 1736 /*
1742 1737 * Don't proxy ereports on an EXTERNAL transport - we won't
1743 1738 * know how to diagnose them with the wrong topology. Note
1744 1739 * that here (and above) we have to hold/release the event in
1745 1740 * order for it to be freed.
1746 1741 */
1747 1742 fmd_event_hold(e);
1748 1743 fmd_event_rele(e);
1749 1744 } else if (isproto == FMD_B_TRUE)
1750 1745 fmd_dispq_dispatch(dp->d_disp, e, class);
1751 1746 else
1752 1747 fmd_modhash_dispatch(dp->d_mod_hash, e);
1753 1748 done:
1754 1749 (void) pthread_mutex_lock(&xip->xi_lock);
1755 1750
1756 1751 ASSERT(xip->xi_busy != 0);
1757 1752 xip->xi_busy--;
1758 1753
1759 1754 (void) pthread_cond_broadcast(&xip->xi_cv);
1760 1755 (void) pthread_mutex_unlock(&xip->xi_lock);
1761 1756 }
1762 1757
1763 1758 void
1764 1759 fmd_xprt_uuclose(fmd_xprt_t *xp, const char *uuid)
1765 1760 {
1766 1761 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
1767 1762
1768 1763 fmd_event_t *e;
1769 1764 nvlist_t *nvl;
1770 1765 char *s;
1771 1766
1772 1767 if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY)
1773 1768 return; /* read-only transports do not proxy uuclose */
1774 1769
1775 1770 TRACE((FMD_DBG_XPRT, "xprt %u closing case %s\n", xip->xi_id, uuid));
1776 1771
1777 1772 nvl = fmd_protocol_xprt_uuclose(xip->xi_queue->eq_mod,
1778 1773 "resource.fm.xprt.uuclose", xip->xi_version, uuid);
1779 1774
1780 1775 (void) nvlist_lookup_string(nvl, FM_CLASS, &s);
1781 1776 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s);
1782 1777 fmd_eventq_insert_at_time(xip->xi_queue, e);
1783 1778 }
1784 1779
1785 1780 /*
1786 1781 * On proxy side, send back uuresolved request to diagnosing side
1787 1782 */
1788 1783 void
1789 1784 fmd_xprt_uuresolved(fmd_xprt_t *xp, const char *uuid)
1790 1785 {
1791 1786 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
1792 1787
1793 1788 fmd_event_t *e;
1794 1789 nvlist_t *nvl;
1795 1790 char *s;
1796 1791
1797 1792 if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY)
1798 1793 return; /* read-only transports do not proxy uuresolved */
1799 1794
1800 1795 TRACE((FMD_DBG_XPRT, "xprt %u resolving case %s\n", xip->xi_id, uuid));
1801 1796
1802 1797 nvl = fmd_protocol_xprt_uuresolved(xip->xi_queue->eq_mod,
1803 1798 "resource.fm.xprt.uuresolved", xip->xi_version, uuid);
1804 1799
1805 1800 (void) nvlist_lookup_string(nvl, FM_CLASS, &s);
1806 1801 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s);
1807 1802 fmd_eventq_insert_at_time(xip->xi_queue, e);
1808 1803 }
1809 1804
1810 1805 /*
1811 1806 * On proxy side, send back repair/acquit/etc request to diagnosing side
1812 1807 */
1813 1808 void
1814 1809 fmd_xprt_updated(fmd_xprt_t *xp, const char *uuid, uint8_t *statusp,
1815 1810 uint8_t *has_asrup, uint_t nelem)
1816 1811 {
1817 1812 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
1818 1813
1819 1814 fmd_event_t *e;
1820 1815 nvlist_t *nvl;
1821 1816 char *s;
1822 1817
1823 1818 if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY)
1824 1819 return; /* read-only transports do not support remote repairs */
1825 1820
1826 1821 TRACE((FMD_DBG_XPRT, "xprt %u updating case %s\n", xip->xi_id, uuid));
1827 1822
1828 1823 nvl = fmd_protocol_xprt_updated(xip->xi_queue->eq_mod,
1829 1824 "resource.fm.xprt.updated", xip->xi_version, uuid, statusp,
1830 1825 has_asrup, nelem);
1831 1826
1832 1827 (void) nvlist_lookup_string(nvl, FM_CLASS, &s);
1833 1828 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s);
1834 1829 fmd_eventq_insert_at_time(xip->xi_queue, e);
1835 1830 }
1836 1831
1837 1832 /*
1838 1833 * Insert the specified class into our remote subscription hash. If the class
1839 1834 * is already present, bump the reference count; otherwise add it to the hash
1840 1835 * and then enqueue an event for our remote peer to proxy our subscription.
1841 1836 */
1842 1837 void
1843 1838 fmd_xprt_subscribe(fmd_xprt_t *xp, const char *class)
1844 1839 {
1845 1840 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
1846 1841
1847 1842 uint_t refs;
1848 1843 nvlist_t *nvl;
1849 1844 fmd_event_t *e;
1850 1845 char *s;
1851 1846
1852 1847 if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY)
1853 1848 return; /* read-only transports do not proxy subscriptions */
1854 1849
1855 1850 if (!(xip->xi_flags & FMD_XPRT_SUBSCRIBER))
1856 1851 return; /* transport is not yet an active subscriber */
1857 1852
1858 1853 (void) pthread_mutex_lock(&xip->xi_lock);
1859 1854 refs = fmd_xprt_class_hash_insert(xip, &xip->xi_rsub, class);
1860 1855 (void) pthread_mutex_unlock(&xip->xi_lock);
1861 1856
1862 1857 if (refs > 1)
1863 1858 return; /* we've already asked our peer for this subscription */
1864 1859
1865 1860 fmd_dprintf(FMD_DBG_XPRT,
1866 1861 "xprt %u subscribing to %s\n", xip->xi_id, class);
1867 1862
1868 1863 nvl = fmd_protocol_xprt_sub(xip->xi_queue->eq_mod,
1869 1864 "resource.fm.xprt.subscribe", xip->xi_version, class);
1870 1865
1871 1866 (void) nvlist_lookup_string(nvl, FM_CLASS, &s);
1872 1867 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s);
1873 1868 fmd_eventq_insert_at_time(xip->xi_queue, e);
1874 1869 }
1875 1870
1876 1871 /*
1877 1872 * Delete the specified class from the remote subscription hash. If the
1878 1873 * reference count drops to zero, ask our remote peer to unsubscribe by proxy.
1879 1874 */
1880 1875 void
1881 1876 fmd_xprt_unsubscribe(fmd_xprt_t *xp, const char *class)
1882 1877 {
1883 1878 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
1884 1879
1885 1880 uint_t refs;
1886 1881 nvlist_t *nvl;
1887 1882 fmd_event_t *e;
1888 1883 char *s;
1889 1884
1890 1885 if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY)
1891 1886 return; /* read-only transports do not proxy subscriptions */
1892 1887
1893 1888 if (!(xip->xi_flags & FMD_XPRT_SUBSCRIBER))
1894 1889 return; /* transport is not yet an active subscriber */
1895 1890
1896 1891 /*
1897 1892 * If the subscription reference count drops to zero in xi_rsub, insert
1898 1893 * an entry into the xi_usub hash indicating we await an unsuback event.
1899 1894 */
1900 1895 (void) pthread_mutex_lock(&xip->xi_lock);
1901 1896
1902 1897 if ((refs = fmd_xprt_class_hash_delete(xip, &xip->xi_rsub, class)) == 0)
1903 1898 (void) fmd_xprt_class_hash_insert(xip, &xip->xi_usub, class);
1904 1899
1905 1900 (void) pthread_mutex_unlock(&xip->xi_lock);
1906 1901
1907 1902 if (refs != 0)
1908 1903 return; /* other subscriptions for this class still active */
1909 1904
1910 1905 fmd_dprintf(FMD_DBG_XPRT,
1911 1906 "xprt %u unsubscribing from %s\n", xip->xi_id, class);
1912 1907
1913 1908 nvl = fmd_protocol_xprt_sub(xip->xi_queue->eq_mod,
1914 1909 "resource.fm.xprt.unsubscribe", xip->xi_version, class);
1915 1910
1916 1911 (void) nvlist_lookup_string(nvl, FM_CLASS, &s);
1917 1912 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s);
1918 1913 fmd_eventq_insert_at_time(xip->xi_queue, e);
1919 1914 }
1920 1915
1921 1916 static void
1922 1917 fmd_xprt_subscribe_xid(fmd_idspace_t *ids, id_t id, void *class)
1923 1918 {
1924 1919 fmd_xprt_t *xp;
1925 1920
1926 1921 if ((xp = fmd_idspace_hold(ids, id)) != NULL) {
1927 1922 fmd_xprt_subscribe(xp, class);
1928 1923 fmd_idspace_rele(ids, id);
1929 1924 }
1930 1925 }
1931 1926
1932 1927 void
1933 1928 fmd_xprt_subscribe_all(const char *class)
1934 1929 {
1935 1930 fmd_idspace_t *ids = fmd.d_xprt_ids;
1936 1931
1937 1932 if (ids->ids_count != 0)
1938 1933 fmd_idspace_apply(ids, fmd_xprt_subscribe_xid, (void *)class);
1939 1934 }
1940 1935
1941 1936 static void
1942 1937 fmd_xprt_unsubscribe_xid(fmd_idspace_t *ids, id_t id, void *class)
1943 1938 {
1944 1939 fmd_xprt_t *xp;
1945 1940
1946 1941 if ((xp = fmd_idspace_hold(ids, id)) != NULL) {
1947 1942 fmd_xprt_unsubscribe(xp, class);
1948 1943 fmd_idspace_rele(ids, id);
1949 1944 }
1950 1945 }
1951 1946
1952 1947 void
1953 1948 fmd_xprt_unsubscribe_all(const char *class)
1954 1949 {
1955 1950 fmd_idspace_t *ids = fmd.d_xprt_ids;
1956 1951
1957 1952 if (ids->ids_count != 0)
1958 1953 fmd_idspace_apply(ids, fmd_xprt_unsubscribe_xid, (void *)class);
1959 1954 }
1960 1955
1961 1956 /*ARGSUSED*/
1962 1957 static void
1963 1958 fmd_xprt_suspend_xid(fmd_idspace_t *ids, id_t id, void *arg)
1964 1959 {
1965 1960 fmd_xprt_t *xp;
1966 1961
1967 1962 if ((xp = fmd_idspace_hold(ids, id)) != NULL) {
1968 1963 fmd_xprt_xsuspend(xp, FMD_XPRT_DSUSPENDED);
1969 1964 fmd_idspace_rele(ids, id);
1970 1965 }
1971 1966 }
1972 1967
1973 1968 void
1974 1969 fmd_xprt_suspend_all(void)
1975 1970 {
1976 1971 fmd_idspace_t *ids = fmd.d_xprt_ids;
1977 1972
1978 1973 (void) pthread_mutex_lock(&fmd.d_xprt_lock);
1979 1974
1980 1975 if (fmd.d_xprt_suspend++ != 0) {
1981 1976 (void) pthread_mutex_unlock(&fmd.d_xprt_lock);
1982 1977 return; /* already suspended */
1983 1978 }
1984 1979
1985 1980 if (ids->ids_count != 0)
1986 1981 fmd_idspace_apply(ids, fmd_xprt_suspend_xid, NULL);
1987 1982
1988 1983 (void) pthread_mutex_unlock(&fmd.d_xprt_lock);
1989 1984 }
1990 1985
1991 1986 /*ARGSUSED*/
1992 1987 static void
1993 1988 fmd_xprt_resume_xid(fmd_idspace_t *ids, id_t id, void *arg)
1994 1989 {
1995 1990 fmd_xprt_t *xp;
1996 1991
1997 1992 if ((xp = fmd_idspace_hold(ids, id)) != NULL) {
1998 1993 fmd_xprt_xresume(xp, FMD_XPRT_DSUSPENDED);
1999 1994 fmd_idspace_rele(ids, id);
2000 1995 }
2001 1996 }
2002 1997
2003 1998 void
2004 1999 fmd_xprt_resume_all(void)
2005 2000 {
2006 2001 fmd_idspace_t *ids = fmd.d_xprt_ids;
2007 2002
2008 2003 (void) pthread_mutex_lock(&fmd.d_xprt_lock);
2009 2004
2010 2005 if (fmd.d_xprt_suspend == 0)
2011 2006 fmd_panic("fmd_xprt_suspend/resume_all mismatch\n");
2012 2007
2013 2008 if (--fmd.d_xprt_suspend != 0) {
2014 2009 (void) pthread_mutex_unlock(&fmd.d_xprt_lock);
2015 2010 return; /* not ready to be resumed */
2016 2011 }
2017 2012
2018 2013 if (ids->ids_count != 0)
2019 2014 fmd_idspace_apply(ids, fmd_xprt_resume_xid, NULL);
2020 2015
2021 2016 (void) pthread_mutex_unlock(&fmd.d_xprt_lock);
2022 2017 }
↓ open down ↓ |
664 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX