4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Topology nodes, tnode_t, are data structures containing per-FMRI
29 * information and are linked together to form the topology tree.
30 * Nodes are created during the enumeration process of topo_snap_hold()
31 * and destroyed during topo_snap_rele(). For the most part, tnode_t data
32 * is read-only and no lock protection is required. Nodes are
33 * held in place during tree walk functions. Tree walk functions
34 * may access node data safely without locks. The exception to this rule
35 * is data associated with node properties (topo_prop.c). Properties
36 * may change at anytime and are protected by a per-property locking
39 * Enumerator plugin modules may also safely access topology nodes within their
40 * scope of operation: the parent node passed into the enumeration op or those
41 * nodes created by the enumerator. Enumeration occurs only during
42 * topo_snap_hold() where a per-topo_hdl_t lock prevents multi-threaded access
43 * to the topology trees.
45 * Enumerator method operation functions may safely access and change topology
46 * node property data, and contruct or destroy child nodes for the node
47 * on which the operation applies. The method may also be called to destroy
48 * the node for which the method operation is called. This permits
49 * dynamic topology tree snapshots and partial enumerations for branches that
50 * may not be needed right away.
54 * Nodes are created when an enumerator calls topo_node_bind(). Prior to
55 * calling topo_node_bind(), the enumerator should have reserved a range of
56 * node instances with topo_node_range_create(). topo_node_range_create()
57 * does not allocate any node resources but creates the infrastruture
58 * required for a fully populated topology level. This allows enumerators
59 * reading from a <scheme>-topology.xml file to parse the file for a range
60 * of resources before confirming the existence of a resource via a helper
61 * plugin. Only when the resource has been confirmed to exist should
64 * Node range and node linkage and unlinkage is performed during enumeration and
65 * method operations when it is safe to change node hash lists. Nodes and node
66 * ranges are deallocated when all references to the node have been released:
67 * last walk completes and topo_snap_rele() is called.
71 * Each parent node may have one or more ranges of child nodes. Each range
72 * is uniquely named and serves as a hash list of like sibling nodes with
73 * different instance numbers. A parent may have more than one node hash
74 * (child range). If that is the case, the hash lists are strung together to
75 * form sibling relationships between ranges. Hash/Ranges are sparsely
76 * populated with only nodes that have represented resources in the system.
80 * | tnode_t | -----------------------------
81 * | tn_phash ---> | topo_nodehash_t |
82 * | (children)| | th_nodearr (instances)|
83 * ----------------- | ------------------- |
84 * | ---| 0 | 1 | ...| N | |
85 * | | ------------------- | -------------------
86 * | | th_list (siblings) ----->| topo_nodehash_t |
87 * | | | -------------------
88 * ---|-------------------------
97 * Facility nodes are always leaf nodes in the topology and represent a FMRI
98 * sensor or indicator facility for the path to which it is connected.
99 * Facility nodes are bound to the topology with topo_node_facbind() and
100 * unbound with topo_node_unbind().
106 #include <sys/fm/protocol.h>
107 #include <topo_alloc.h>
108 #include <topo_error.h>
109 #include <topo_list.h>
110 #include <topo_method.h>
111 #include <topo_subr.h>
112 #include <topo_tree.h>
114 static topo_pgroup_info_t protocol_pgroup
= {
115 TOPO_PGROUP_PROTOCOL
,
116 TOPO_STABILITY_PRIVATE
,
117 TOPO_STABILITY_PRIVATE
,
121 static const topo_pgroup_info_t auth_pgroup
= {
123 TOPO_STABILITY_PRIVATE
,
124 TOPO_STABILITY_PRIVATE
,
129 topo_node_destroy(tnode_t
*node
)
132 tnode_t
*pnode
= node
->tn_parent
;
133 topo_nodehash_t
*nhp
;
134 topo_mod_t
*hmod
, *mod
= node
->tn_enum
;
139 topo_dprintf(mod
->tm_hdl
, TOPO_DBG_MODSVC
, "destroying node %s=%d\n",
140 topo_node_name(node
), topo_node_instance(node
));
142 assert(node
->tn_refs
== 0);
145 * If not a root node, remove this node from the parent's node hash
148 if (!(node
->tn_state
& TOPO_NODE_ROOT
)) {
149 topo_node_lock(pnode
);
151 nhp
= node
->tn_phash
;
152 for (i
= 0; i
< nhp
->th_arrlen
; i
++) {
153 if (node
== nhp
->th_nodearr
[i
]) {
154 nhp
->th_nodearr
[i
] = NULL
;
157 * Release hold on parent
160 if (pnode
->tn_refs
== 0)
161 topo_node_destroy(pnode
);
164 topo_node_unlock(pnode
);
167 topo_node_unlock(node
);
170 * Allow enumerator to clean-up private data and then release
173 if (mod
->tm_info
->tmi_ops
->tmo_release
!= NULL
)
174 mod
->tm_info
->tmi_ops
->tmo_release(mod
, node
);
176 topo_method_unregister_all(mod
, node
);
179 * Destroy all node hash lists
181 while ((nhp
= topo_list_next(&node
->tn_children
)) != NULL
) {
182 for (i
= 0; i
< nhp
->th_arrlen
; i
++) {
183 assert(nhp
->th_nodearr
[i
] == NULL
);
186 topo_mod_strfree(hmod
, nhp
->th_name
);
187 topo_mod_free(hmod
, nhp
->th_nodearr
,
188 nhp
->th_arrlen
* sizeof (tnode_t
*));
189 topo_list_delete(&node
->tn_children
, nhp
);
190 topo_mod_free(hmod
, nhp
, sizeof (topo_nodehash_t
));
195 * Destroy all property data structures, free the node and release
196 * the module that created it
198 topo_pgroup_destroy_all(node
);
199 topo_mod_free(mod
, node
, sizeof (tnode_t
));
204 topo_node_lock(tnode_t
*node
)
206 (void) pthread_mutex_lock(&node
->tn_lock
);
210 topo_node_unlock(tnode_t
*node
)
212 (void) pthread_mutex_unlock(&node
->tn_lock
);
216 topo_node_hold(tnode_t
*node
)
218 topo_node_lock(node
);
220 topo_node_unlock(node
);
224 topo_node_rele(tnode_t
*node
)
226 topo_node_lock(node
);
230 * Ok to remove this node from the topo tree and destroy it
232 if (node
->tn_refs
== 0)
233 topo_node_destroy(node
);
235 topo_node_unlock(node
);
239 topo_node_name(tnode_t
*node
)
241 return (node
->tn_name
);
245 topo_node_instance(tnode_t
*node
)
247 return (node
->tn_instance
);
251 topo_node_parent(tnode_t
*node
)
253 return (node
->tn_parent
);
257 topo_node_flags(tnode_t
*node
)
259 return (node
->tn_fflags
);
263 topo_node_setspecific(tnode_t
*node
, void *data
)
265 node
->tn_priv
= data
;
269 topo_node_getspecific(tnode_t
*node
)
271 return (node
->tn_priv
);
275 node_create_seterror(topo_mod_t
*mod
, tnode_t
*pnode
, topo_nodehash_t
*nhp
,
278 topo_node_unlock(pnode
);
280 topo_dprintf(mod
->tm_hdl
, TOPO_DBG_ERR
, "unable to insert child:"
281 "%s\n", topo_strerror(err
));
284 if (nhp
->th_name
!= NULL
)
285 topo_mod_strfree(mod
, nhp
->th_name
);
286 if (nhp
->th_nodearr
!= NULL
) {
287 topo_mod_free(mod
, nhp
->th_nodearr
,
288 nhp
->th_arrlen
* sizeof (tnode_t
*));
290 topo_mod_free(mod
, nhp
, sizeof (topo_nodehash_t
));
293 return (topo_mod_seterrno(mod
, err
));
297 topo_node_range_create(topo_mod_t
*mod
, tnode_t
*pnode
, const char *name
,
298 topo_instance_t min
, topo_instance_t max
)
300 topo_nodehash_t
*nhp
;
302 topo_node_lock(pnode
);
304 assert((pnode
->tn_state
& TOPO_NODE_BOUND
) ||
305 (pnode
->tn_state
& TOPO_NODE_ROOT
));
307 for (nhp
= topo_list_next(&pnode
->tn_children
); nhp
!= NULL
;
308 nhp
= topo_list_next(nhp
)) {
309 if (strcmp(nhp
->th_name
, name
) == 0)
310 return (node_create_seterror(mod
, pnode
, NULL
,
314 if (min
< 0 || max
< min
)
315 return (node_create_seterror(mod
, pnode
, NULL
,
318 if ((nhp
= topo_mod_zalloc(mod
, sizeof (topo_nodehash_t
))) == NULL
)
319 return (node_create_seterror(mod
, pnode
, nhp
, EMOD_NOMEM
));
321 if ((nhp
->th_name
= topo_mod_strdup(mod
, name
)) == NULL
)
322 return (node_create_seterror(mod
, pnode
, nhp
, EMOD_NOMEM
));
324 nhp
->th_arrlen
= max
- min
+ 1;
326 if ((nhp
->th_nodearr
= topo_mod_zalloc(mod
,
327 nhp
->th_arrlen
* sizeof (tnode_t
*))) == NULL
)
328 return (node_create_seterror(mod
, pnode
, nhp
, EMOD_NOMEM
));
330 nhp
->th_range
.tr_min
= min
;
331 nhp
->th_range
.tr_max
= max
;
336 * Add these nodes to parent child list
338 topo_list_append(&pnode
->tn_children
, nhp
);
339 topo_node_unlock(pnode
);
341 topo_dprintf(mod
->tm_hdl
, TOPO_DBG_MODSVC
,
342 "created node range %s[%d-%d]\n", name
, min
, max
);
348 topo_node_range_destroy(tnode_t
*pnode
, const char *name
)
351 topo_nodehash_t
*nhp
;
354 topo_node_lock(pnode
);
355 for (nhp
= topo_list_next(&pnode
->tn_children
); nhp
!= NULL
;
356 nhp
= topo_list_next(nhp
)) {
357 if (strcmp(nhp
->th_name
, name
) == 0) {
363 topo_node_unlock(pnode
);
367 for (i
= 0; i
< nhp
->th_arrlen
; i
++)
368 assert(nhp
->th_nodearr
[i
] == NULL
);
370 topo_list_delete(&pnode
->tn_children
, nhp
);
371 topo_node_unlock(pnode
);
374 if (nhp
->th_name
!= NULL
)
375 topo_mod_strfree(mod
, nhp
->th_name
);
376 if (nhp
->th_nodearr
!= NULL
) {
377 topo_mod_free(mod
, nhp
->th_nodearr
,
378 nhp
->th_arrlen
* sizeof (tnode_t
*));
380 topo_mod_free(mod
, nhp
, sizeof (topo_nodehash_t
));
386 topo_node_lookup(tnode_t
*pnode
, const char *name
, topo_instance_t inst
)
390 topo_nodehash_t
*nhp
;
392 topo_dprintf(pnode
->tn_hdl
, TOPO_DBG_MODSVC
,
393 "topo_node_lookup: looking for '%s' instance %d\n", name
, inst
);
395 topo_node_lock(pnode
);
396 for (nhp
= topo_list_next(&pnode
->tn_children
); nhp
!= NULL
;
397 nhp
= topo_list_next(nhp
)) {
398 if (strcmp(nhp
->th_name
, name
) == 0) {
400 if (inst
> nhp
->th_range
.tr_max
||
401 inst
< nhp
->th_range
.tr_min
) {
402 topo_node_unlock(pnode
);
406 h
= topo_node_hash(nhp
, inst
);
407 node
= nhp
->th_nodearr
[h
];
408 topo_node_unlock(pnode
);
412 topo_node_unlock(pnode
);
418 topo_node_hash(topo_nodehash_t
*nhp
, topo_instance_t inst
)
420 return ((inst
- nhp
->th_range
.tr_min
) % nhp
->th_arrlen
);
424 node_bind_seterror(topo_mod_t
*mod
, tnode_t
*pnode
, tnode_t
*node
,
425 boolean_t pnode_locked
, int err
)
428 topo_node_unlock(pnode
);
430 (void) topo_mod_seterrno(mod
, err
);
435 topo_dprintf(mod
->tm_hdl
, TOPO_DBG_ERR
, "unable to bind %s=%d: "
436 "%s\n", (node
->tn_name
!= NULL
? node
->tn_name
: "unknown"),
437 node
->tn_instance
, topo_strerror(err
));
439 topo_node_lock(node
); /* expected to be locked */
440 topo_node_destroy(node
);
446 topo_node_bind(topo_mod_t
*mod
, tnode_t
*pnode
, const char *name
,
447 topo_instance_t inst
, nvlist_t
*fmri
)
451 topo_nodehash_t
*nhp
;
453 topo_node_lock(pnode
);
454 for (nhp
= topo_list_next(&pnode
->tn_children
); nhp
!= NULL
;
455 nhp
= topo_list_next(nhp
)) {
456 if (strcmp(nhp
->th_name
, name
) == 0) {
458 if (inst
> nhp
->th_range
.tr_max
||
459 inst
< nhp
->th_range
.tr_min
)
460 return (node_bind_seterror(mod
, pnode
, NULL
,
461 B_TRUE
, EMOD_NODE_RANGE
));
463 h
= topo_node_hash(nhp
, inst
);
464 if (nhp
->th_nodearr
[h
] != NULL
)
465 return (node_bind_seterror(mod
, pnode
, NULL
,
466 B_TRUE
, EMOD_NODE_BOUND
));
474 return (node_bind_seterror(mod
, pnode
, NULL
, B_TRUE
,
477 if ((node
= topo_mod_zalloc(mod
, sizeof (tnode_t
))) == NULL
)
478 return (node_bind_seterror(mod
, pnode
, NULL
, B_TRUE
,
481 (void) pthread_mutex_init(&node
->tn_lock
, NULL
);
484 node
->tn_hdl
= mod
->tm_hdl
;
485 node
->tn_parent
= pnode
;
486 node
->tn_name
= nhp
->th_name
;
487 node
->tn_instance
= inst
;
488 node
->tn_phash
= nhp
;
491 /* Ref count module that bound this node */
495 return (node_bind_seterror(mod
, pnode
, node
, B_TRUE
,
498 if (topo_pgroup_create(node
, &protocol_pgroup
, &err
) < 0)
499 return (node_bind_seterror(mod
, pnode
, node
, B_TRUE
, err
));
501 if (topo_prop_set_fmri(node
, TOPO_PGROUP_PROTOCOL
, TOPO_PROP_RESOURCE
,
502 TOPO_PROP_IMMUTABLE
, fmri
, &err
) < 0)
503 return (node_bind_seterror(mod
, pnode
, node
, B_TRUE
, err
));
505 topo_dprintf(mod
->tm_hdl
, TOPO_DBG_MODSVC
,
506 "node bound %s=%d/%s=%d\n", topo_node_name(pnode
),
507 topo_node_instance(pnode
), node
->tn_name
, node
->tn_instance
);
509 node
->tn_state
|= TOPO_NODE_BOUND
;
511 topo_node_hold(node
);
512 nhp
->th_nodearr
[h
] = node
;
515 topo_node_unlock(pnode
);
517 if (topo_pgroup_create(node
, &auth_pgroup
, &err
) == 0) {
518 (void) topo_prop_inherit(node
, FM_FMRI_AUTHORITY
,
519 FM_FMRI_AUTH_PRODUCT
, &err
);
520 (void) topo_prop_inherit(node
, FM_FMRI_AUTHORITY
,
521 FM_FMRI_AUTH_PRODUCT_SN
, &err
);
522 (void) topo_prop_inherit(node
, FM_FMRI_AUTHORITY
,
523 FM_FMRI_AUTH_CHASSIS
, &err
);
524 (void) topo_prop_inherit(node
, FM_FMRI_AUTHORITY
,
525 FM_FMRI_AUTH_SERVER
, &err
);
532 topo_node_facbind(topo_mod_t
*mod
, tnode_t
*pnode
, const char *name
,
537 topo_nodehash_t
*nhp
;
538 topo_instance_t inst
= 0;
539 nvlist_t
*pfmri
, *fnvl
;
542 * Create a single entry range for this facility
544 if (topo_node_range_create(mod
, pnode
, name
, 0, 0) < 0)
545 return (NULL
); /* mod errno set */
547 topo_node_hold(pnode
);
548 topo_node_lock(pnode
);
549 for (nhp
= topo_list_next(&pnode
->tn_children
); nhp
!= NULL
;
550 nhp
= topo_list_next(nhp
)) {
551 if (strcmp(nhp
->th_name
, name
) == 0) {
553 if (inst
> nhp
->th_range
.tr_max
||
554 inst
< nhp
->th_range
.tr_min
) {
555 topo_node_rele(pnode
);
556 return (node_bind_seterror(mod
, pnode
, NULL
,
557 B_TRUE
, EMOD_NVL_INVAL
));
559 h
= topo_node_hash(nhp
, inst
);
560 if (nhp
->th_nodearr
[h
] != NULL
) {
561 topo_node_rele(pnode
);
562 return (node_bind_seterror(mod
, pnode
, NULL
,
563 B_TRUE
, EMOD_NODE_BOUND
));
569 topo_node_unlock(pnode
);
572 topo_node_rele(pnode
);
573 return (node_bind_seterror(mod
, pnode
, NULL
, B_FALSE
,
576 if ((node
= topo_mod_zalloc(mod
, sizeof (tnode_t
))) == NULL
) {
577 topo_node_rele(pnode
);
578 return (node_bind_seterror(mod
, pnode
, NULL
, B_FALSE
,
582 (void) pthread_mutex_init(&node
->tn_lock
, NULL
);
585 node
->tn_hdl
= mod
->tm_hdl
;
586 node
->tn_parent
= pnode
;
587 node
->tn_name
= nhp
->th_name
;
588 node
->tn_instance
= inst
;
589 node
->tn_phash
= nhp
;
591 node
->tn_fflags
= TOPO_NODE_FACILITY
;
593 /* Ref count module that bound this node */
596 if (topo_pgroup_create(node
, &protocol_pgroup
, &err
) < 0) {
597 topo_node_rele(pnode
);
598 return (node_bind_seterror(mod
, pnode
, node
, B_FALSE
, err
));
600 if (topo_mod_nvalloc(mod
, &fnvl
, NV_UNIQUE_NAME
) < 0) {
601 topo_node_rele(pnode
);
602 return (node_bind_seterror(mod
, pnode
, node
, B_FALSE
,
605 if (nvlist_add_string(fnvl
, FM_FMRI_FACILITY_NAME
, name
) != 0 ||
606 nvlist_add_string(fnvl
, FM_FMRI_FACILITY_TYPE
, type
) != 0) {
608 topo_node_rele(pnode
);
609 return (node_bind_seterror(mod
, pnode
, node
, B_FALSE
,
613 if (topo_node_resource(pnode
, &pfmri
, &err
) < 0) {
615 topo_node_rele(pnode
);
616 return (node_bind_seterror(mod
, pnode
, node
, B_FALSE
, err
));
619 if (nvlist_add_nvlist(pfmri
, FM_FMRI_FACILITY
, fnvl
) != 0) {
622 topo_node_rele(pnode
);
623 return (node_bind_seterror(mod
, pnode
, node
, B_FALSE
,
629 if (topo_prop_set_fmri(node
, TOPO_PGROUP_PROTOCOL
, TOPO_PROP_RESOURCE
,
630 TOPO_PROP_IMMUTABLE
, pfmri
, &err
) < 0) {
632 topo_node_rele(pnode
);
633 return (node_bind_seterror(mod
, pnode
, node
, B_FALSE
, err
));
638 topo_dprintf(mod
->tm_hdl
, TOPO_DBG_MODSVC
,
639 "facility node bound %s=%s\n", type
, node
->tn_name
);
641 node
->tn_state
|= TOPO_NODE_BOUND
;
643 topo_node_hold(node
);
644 nhp
->th_nodearr
[h
] = node
;
646 topo_node_lock(pnode
);
648 topo_node_unlock(pnode
);
649 topo_node_rele(pnode
);
651 if (topo_pgroup_create(node
, &auth_pgroup
, &err
) == 0) {
652 (void) topo_prop_inherit(node
, FM_FMRI_AUTHORITY
,
653 FM_FMRI_AUTH_PRODUCT
, &err
);
654 (void) topo_prop_inherit(node
, FM_FMRI_AUTHORITY
,
655 FM_FMRI_AUTH_PRODUCT_SN
, &err
);
656 (void) topo_prop_inherit(node
, FM_FMRI_AUTHORITY
,
657 FM_FMRI_AUTH_CHASSIS
, &err
);
658 (void) topo_prop_inherit(node
, FM_FMRI_AUTHORITY
,
659 FM_FMRI_AUTH_SERVER
, &err
);
666 topo_node_facility(topo_hdl_t
*thp
, tnode_t
*node
, const char *fac_type
,
667 uint32_t fac_subtype
, topo_faclist_t
*faclist
, int *errp
)
670 nvlist_t
*rsrc
, *fac
;
672 uint32_t tmp_facsubtype
;
673 boolean_t list_empty
= 1;
674 topo_faclist_t
*fac_ele
;
676 bzero(faclist
, sizeof (topo_faclist_t
));
677 for (tmp
= topo_child_first(node
); tmp
!= NULL
;
678 tmp
= topo_child_next(node
, tmp
)) {
682 * If it's not a facility node, move on
684 if (topo_node_flags(tmp
) != TOPO_NODE_FACILITY
) {
690 * Lookup whether the fac type is sensor or indicator and if
691 * it's not the type we're looking for, move on
693 if (topo_node_resource(tmp
, &rsrc
, errp
) != 0) {
694 topo_dprintf(thp
, TOPO_DBG_ERR
,
695 "Failed to get resource for node %s=%d (%s)\n",
696 topo_node_name(node
), topo_node_instance(node
),
697 topo_strerror(*errp
));
701 if ((nvlist_lookup_nvlist(rsrc
, "facility", &fac
) != 0) ||
702 (nvlist_lookup_string(fac
, FM_FMRI_FACILITY_TYPE
,
703 &tmp_factype
) != 0)) {
710 if (strcmp(fac_type
, tmp_factype
) != 0) {
718 * Finally, look up the subtype, which is a property in the
719 * facility propgroup. If it's a match return a pointer to the
720 * node. Otherwise, move on.
722 if (topo_prop_get_uint32(tmp
, TOPO_PGROUP_FACILITY
,
723 TOPO_FACILITY_TYPE
, &tmp_facsubtype
, errp
) != 0) {
727 if (fac_subtype
== tmp_facsubtype
||
728 fac_subtype
== TOPO_FAC_TYPE_ANY
) {
729 if ((fac_ele
= topo_mod_zalloc(tmp
->tn_enum
,
730 sizeof (topo_faclist_t
))) == NULL
) {
735 fac_ele
->tf_node
= tmp
;
736 topo_list_append(&faclist
->tf_list
, fac_ele
);
743 *errp
= ETOPO_FAC_NOENT
;
750 topo_node_unbind(tnode_t
*node
)
755 topo_node_lock(node
);
756 if (!(node
->tn_state
& TOPO_NODE_BOUND
)) {
757 topo_node_unlock(node
);
761 node
->tn_state
&= ~TOPO_NODE_BOUND
;
762 topo_node_unlock(node
);
764 topo_dprintf(node
->tn_hdl
, TOPO_DBG_MODSVC
,
765 "node unbound %s=%d/%s=%d refs = %d\n",
766 topo_node_name(node
->tn_parent
),
767 topo_node_instance(node
->tn_parent
), node
->tn_name
,
768 node
->tn_instance
, node
->tn_refs
);
770 topo_node_rele(node
);
775 topo_node_present(tnode_t
*node
)
782 topo_node_contains(tnode_t
*er
, tnode_t
*ee
)
789 topo_node_unusable(tnode_t
*node
)
795 topo_node_walk_init(topo_hdl_t
*thp
, topo_mod_t
*mod
, tnode_t
*node
,
796 int (*cb_f
)(), void *pdata
, int *errp
)
801 topo_node_hold(node
);
803 if ((wp
= topo_hdl_zalloc(thp
, sizeof (topo_walk_t
))) == NULL
) {
804 *errp
= ETOPO_HDL_NOMEM
;
805 topo_node_rele(node
);
810 * If this is the root of the scheme tree, start with the first
813 topo_node_lock(node
);
814 if (node
->tn_state
& TOPO_NODE_ROOT
) {
815 if ((child
= topo_child_first(node
)) == NULL
) {
816 /* Nothing to walk */
817 *errp
= ETOPO_WALK_EMPTY
;
818 topo_node_unlock(node
);
819 topo_node_rele(node
);
820 topo_hdl_free(thp
, wp
, sizeof (topo_walk_t
));
823 topo_node_unlock(node
);
824 topo_node_hold(child
);
827 topo_node_unlock(node
);
828 topo_node_hold(node
); /* rele at walk end */
834 wp
->tw_pdata
= pdata
;
842 * Walk the direct children of the given node.
845 topo_node_child_walk(topo_hdl_t
*thp
, tnode_t
*pnode
, topo_walk_cb_t cb_f
,
846 void *arg
, int *errp
)
848 int ret
= TOPO_WALK_TERMINATE
;
851 topo_node_hold(pnode
);
856 topo_node_lock(pnode
);
857 cnode
= topo_child_first(pnode
);
858 topo_node_unlock(pnode
);
861 *errp
= ETOPO_WALK_EMPTY
;
866 while (cnode
!= NULL
) {
870 * Call the walker callback:
872 topo_node_hold(cnode
);
873 iret
= cb_f(thp
, cnode
, arg
);
874 topo_node_rele(cnode
);
875 if (iret
!= TOPO_WALK_NEXT
) {
883 topo_node_lock(pnode
);
884 cnode
= topo_child_next(pnode
, cnode
);
885 topo_node_unlock(pnode
);
889 topo_node_rele(pnode
);