Mercurial > illumos > illumos-gate
changeset 5029:ffbab30c82bd
6592150 PICL SNMP and PRI plug-ins don't handle picld being sent a SIGHUP
author | fw157321 |
---|---|
date | Tue, 11 Sep 2007 16:39:42 -0700 |
parents | 71f71fe9e4b9 |
children | 15cab3a79834 |
files | usr/src/cmd/picl/picld/picl.xml usr/src/cmd/picl/plugins/sun4v/pri/init.c usr/src/cmd/picl/plugins/sun4v/pri/io_dev_label.c usr/src/cmd/picl/plugins/sun4v/pri/mem_prop_update.c usr/src/cmd/picl/plugins/sun4v/pri/priplugin.c usr/src/cmd/picl/plugins/sun4v/pri/priplugin.h usr/src/cmd/picl/plugins/sun4v/snmp/snmpplugin.c |
diffstat | 7 files changed, 346 insertions(+), 94 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/cmd/picl/picld/picl.xml Tue Sep 11 16:36:53 2007 -0700 +++ b/usr/src/cmd/picl/picld/picl.xml Tue Sep 11 16:39:42 2007 -0700 @@ -60,6 +60,12 @@ <exec_method type='method' + name='refresh' + exec=':kill -1' + timeout_seconds='60' /> + + <exec_method + type='method' name='start' exec='/usr/lib/picl/picld' timeout_seconds='60' />
--- a/usr/src/cmd/picl/plugins/sun4v/pri/init.c Tue Sep 11 16:36:53 2007 -0700 +++ b/usr/src/cmd/picl/plugins/sun4v/pri/init.c Tue Sep 11 16:39:42 2007 -0700 @@ -35,29 +35,40 @@ static void pri_free(void *bufp, size_t size); static uint64_t *md_bufp = NULL; +static uint64_t *new_md_bufp; -md_t * -pri_devinit(uint64_t *tok, md_t *mdp) +int +pri_devinit(uint64_t *tok) { - uint64_t *new_md_bufp; + int status; - + new_md_bufp = NULL; + status = 0; if (pri_get(PRI_WAITGET, tok, &new_md_bufp, malloc, pri_free) == (ssize_t)-1) { pri_debug(LOG_NOTICE, "pri_devinit: can'r read from " "the PRI: %d\n", errno); + status = -1; } if (new_md_bufp == NULL) { - pri_debug(LOG_NOTICE, "pri_devinit: pri_get returned" + pri_debug(LOG_NOTICE, "pri_devinit: pri_get returned " "NULL buffer!\n"); + status = -1; } + return (status); +} + +md_t * +pri_bufinit(md_t *mdp) +{ + if (mdp) md_fini(mdp); if (md_bufp) free(md_bufp); md_bufp = new_md_bufp; - pri_debug(LOG_NOTICE, "pri_devinit: done reading PRI\n"); + pri_debug(LOG_NOTICE, "pri_bufinit: done reading PRI\n"); /* * The PRI and the MD use the same data format so they can be @@ -66,18 +77,18 @@ if (md_bufp) { mdp = md_init_intern(md_bufp, malloc, pri_free); if (mdp == NULL) { - pri_debug(LOG_NOTICE, "pri_devinit: md_init_intern " + pri_debug(LOG_NOTICE, "pri_bufinit: md_init_intern " "failed\n"); free(md_bufp); md_bufp = NULL; } else { - pri_debug(LOG_NOTICE, "pri_devinit: mdi_init_intern " + pri_debug(LOG_NOTICE, "pri_bufinit: mdi_init_intern " "completed successfully\n"); } } else mdp = NULL; - pri_debug(LOG_NOTICE, "pri_devinit: returning\n"); + pri_debug(LOG_NOTICE, "pri_bufinit: returning\n"); return (mdp); } @@ -99,5 +110,4 @@ if (md_bufp) free(md_bufp); md_bufp = NULL; - pri_fini(); }
--- a/usr/src/cmd/picl/plugins/sun4v/pri/io_dev_label.c Tue Sep 11 16:36:53 2007 -0700 +++ b/usr/src/cmd/picl/plugins/sun4v/pri/io_dev_label.c Tue Sep 11 16:39:42 2007 -0700 @@ -28,12 +28,6 @@ #include "priplugin.h" -/* - * These 3 variable are defined and set in mdescplugin.c - */ -extern picl_nodehdl_t root_node; -extern mde_cookie_t rootnode; - static int find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname, const char *pval, picl_nodehdl_t *nodeh); @@ -55,12 +49,14 @@ picl_nodehdl_t platnode, tpn; char busaddr[PICL_PROPNAMELEN_MAX], *p, *q; char path[PICL_PROPNAMELEN_MAX]; - mde_cookie_t *components; + mde_cookie_t *components, md_rootnode; char *type, *nac, *pri_path, *saved_path; if (mdp == NULL) return; + md_rootnode = md_root_node(mdp); + /* * Find and remember the roots of the /frutree and /platform trees. */ @@ -86,7 +82,7 @@ return; } - component_count = md_scan_dag(mdp, rootnode, + component_count = md_scan_dag(mdp, md_rootnode, md_find_name(mdp, "component"), md_find_name(mdp, "fwd"), components);
--- a/usr/src/cmd/picl/plugins/sun4v/pri/mem_prop_update.c Tue Sep 11 16:36:53 2007 -0700 +++ b/usr/src/cmd/picl/plugins/sun4v/pri/mem_prop_update.c Tue Sep 11 16:39:42 2007 -0700 @@ -36,12 +36,6 @@ #include "priplugin.h" #include "../../common/memcfg/piclmemcfg.h" -/* - * These 3 variable are defined and set in mdescplugin.c - */ -extern picl_nodehdl_t root_node; -extern mde_cookie_t rootnode; - static void add_memory_props(picl_nodehdl_t node, mde_cookie_t memorylistp, md_t *mdp, uint64_t size); @@ -65,7 +59,7 @@ { mde_cookie_t *memorylistp, *segmentlistp, *banklistp; picl_prophdl_t memh, segmenth, bankh; - mde_cookie_t *buf; + mde_cookie_t *buf, md_rootnode; int j, k, num_nodes, interleave, err; int nsegments, nbanks, nmemory; uint64_t memsize, segsize, segbase; @@ -75,6 +69,8 @@ if (mdp == NULL) return (PICL_WALK_CONTINUE); + md_rootnode = md_root_node(mdp); + /* * An absence of nodes or failure to obtain memory for searches * or absence of the /memory node will cause this to fail. @@ -108,7 +104,7 @@ * return PICL_PROPNOTFOUND to get the caller to re-try with * a different property name. */ - nmemory = md_scan_dag(mdp, rootnode, md_find_name(mdp, + nmemory = md_scan_dag(mdp, md_rootnode, md_find_name(mdp, "memory-segments"), md_find_name(mdp, "fwd"), memorylistp); if (nmemory != 1) { pri_debug(LOG_NOTICE,
--- a/usr/src/cmd/picl/plugins/sun4v/pri/priplugin.c Tue Sep 11 16:36:53 2007 -0700 +++ b/usr/src/cmd/picl/plugins/sun4v/pri/priplugin.c Tue Sep 11 16:39:42 2007 -0700 @@ -31,15 +31,22 @@ #pragma init(priplugin_register) /* place in .init section */ -picl_nodehdl_t root_node; -static md_t *mdp; -mde_cookie_t rootnode; +static md_t *mdp; + +static mutex_t rebuild_lock; +static cond_t rebuild_cv; -void priplugin_init(void); -void priplugin_fini(void); +static thread_t pri_worker_thread_id, pri_reader_thread_id; +static boolean_t all_thr_exit = B_FALSE; + +static void priplugin_init(void); +static void priplugin_fini(void); static void event_handler(const char *ename, const void *earg, size_t size, void *cookie); -static void *priplugin_main(void *); +static void *pri_worker_thread(void *arg); +static void *pri_reader_thread(void *arg); +static int remove_old_segments(picl_nodehdl_t node, void *args); + picld_plugin_reg_t priplugin_reg = { PICLD_PLUGIN_VERSION_1, @@ -49,7 +56,7 @@ priplugin_fini }; -void +static void set_prop_info(ptree_propinfo_t *propinfo, int size, char *name, int type) { propinfo->version = PICLD_PLUGIN_VERSION_1; @@ -89,88 +96,266 @@ } } -void +/*ARGSUSED*/ +static int +remove_old_segments(picl_nodehdl_t node, void *args) +{ + int status; + + if ((status = ptree_delete_node(node)) == PICL_SUCCESS) + ptree_destroy_node(node); + else + pri_debug(LOG_NOTICE, "remove_old_segments: can't delete " + "segment node: %s\n", picl_strerror(status)); + + return (PICL_WALK_CONTINUE); +} + +static void priplugin_init(void) { int status; - pri_debug(LOG_NOTICE, "priplugin: mem tree and io label thread " "being created; callbacks being registered\n"); - /* - * register event_handler for both "sysevent-device-added" and - * and for "sysevent-device-removed" PICL events - */ - (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, - event_handler, NULL); - (void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE, - event_handler, NULL); + all_thr_exit = B_FALSE; + + (void) mutex_init(&rebuild_lock, USYNC_THREAD, NULL); + (void) cond_init(&rebuild_cv, USYNC_THREAD, NULL); - if ((status = thr_create(NULL, NULL, priplugin_main, NULL, THR_BOUND, - NULL)) < 0) { - pri_debug(LOG_NOTICE, "priplugin: can't create main thread: " + if ((status = thr_create(NULL, NULL, pri_worker_thread, NULL, THR_BOUND, + &pri_worker_thread_id)) < 0) { + pri_debug(LOG_NOTICE, "priplugin: can't create worker thread: " + "%d\n", status); + all_thr_exit = B_TRUE; + (void) mutex_destroy(&rebuild_lock); + (void) cond_destroy(&rebuild_cv); + } else if ((status = thr_create(NULL, NULL, pri_reader_thread, NULL, + THR_BOUND, &pri_reader_thread_id)) < 0) { + pri_debug(LOG_NOTICE, "priplugin: can't create reader thread: " "%d\n", status); - priplugin_fini(); + (void) mutex_lock(&rebuild_lock); + all_thr_exit = B_TRUE; + (void) cond_signal(&rebuild_cv); + (void) mutex_unlock(&rebuild_lock); + (void) thr_join(pri_worker_thread_id, NULL, NULL); + (void) mutex_destroy(&rebuild_lock); + (void) cond_destroy(&rebuild_cv); + } else { + pri_debug(LOG_NOTICE, "priplugin_init: worker and reader " + "threads created - registering event handlers\n"); + /* + * register event_handler for both "sysevent-device-added", + * "sysevent_device_removed", and for + * "sysevent-dr-app-state-change" PICL events + */ + (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, + event_handler, NULL); + (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED, + event_handler, NULL); + (void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE, + event_handler, NULL); } } +/* + * This thread handles the main processing of PRI data. It is woken + * up by either the event handler, to process a PICL event, or it is + * woken up by the PRI reader thread which has just fetched a new + * copy of the PRI. + */ /*ARGSUSED*/ static void * -priplugin_main(void *arg) +pri_worker_thread(void *arg) { int status; + picl_nodehdl_t picl_root_node; + + pri_debug(LOG_NOTICE, "pri_worker_thread: start\n"); + + (void) mutex_lock(&rebuild_lock); + while (1) { + (void) cond_wait(&rebuild_cv, &rebuild_lock); + + if (all_thr_exit == B_TRUE) { + (void) mutex_unlock(&rebuild_lock); + pri_debug(LOG_NOTICE, "pri_worker_thread: time to " + "exit\n"); + break; + } + + status = ptree_get_root(&picl_root_node); + if (status != PICL_SUCCESS) { + pri_debug(LOG_NOTICE, "pri_worker_thread: " + "can't get picl tree root node: %s\n", + picl_strerror(status)); + continue; + } + + pri_debug(LOG_NOTICE, "pri_worker_thread: have root picl " + "and PRI nodes\n"); + + status = ptree_walk_tree_by_class(picl_root_node, + "memory-segment", NULL, remove_old_segments); + if (status != PICL_SUCCESS) { + pri_debug(LOG_NOTICE, "pri_worker_thread: can't remove " + "old memory segments: \n", picl_strerror(status)); + } else + pri_debug(LOG_NOTICE, "pri_worker_thread: old memory " + "segments removed\n"); + + status = ptree_walk_tree_by_class(picl_root_node, "memory", + (void *) mdp, add_mem_prop); + if (status != PICL_SUCCESS) { + pri_debug(LOG_NOTICE, "pri_worker_thread: memory " + "segments walk failed: \n", picl_strerror(status)); + } else + pri_debug(LOG_NOTICE, "pri_worker_thread: success " + "walking memory node\n"); + + io_dev_addlabel(mdp); + } + pri_debug(LOG_NOTICE, "pri_worker_thread: exiting\n"); + return (NULL); +} + +/* + * This thread camps out in the PRI driver, waiting for it to return + * the contents of a new PRI. When the PRI is changed this thread + * reads that data and prepares it for processing by the worker thread. + * It then signals the worker thread to process the new PRI data. + */ +/*ARGSUSED*/ +static void * +pri_reader_thread(void *arg) +{ uint64_t tok; + int status, count; + + pri_debug(LOG_NOTICE, "pri_reader_thread: thread start\n"); if (pri_init() != 0) { - pri_debug(LOG_NOTICE, "priplugin_main: pri_init failed\n"); + pri_debug(LOG_NOTICE, "pri_reader_thread: pri_init failed\n"); return (NULL); } - pri_debug(LOG_NOTICE, "priplugin: thread entered\n"); - status = ptree_get_root(&root_node); - if (status != PICL_SUCCESS) { - pri_debug(LOG_NOTICE, "priplugin: can't get picl root " - "node\n"); - priplugin_fini(); - return (NULL); + /* + * It's entirely possible that a new PRI may get pushed while + * the worker thread is processing the previous PRI. We will + * wait until the worker is finished, then flush the old contents + * and wake up the worker again to process the new data. + */ + mdp = NULL; + tok = 0; + count = 0; + while (1) { + /* + * The _fini() function will close the PRI's fd, which will + * cause this function to break out of waiting in the PRI + * driver and return an error. + */ + status = pri_devinit(&tok); + + (void) mutex_lock(&rebuild_lock); + if (all_thr_exit == B_TRUE) { + (void) mutex_unlock(&rebuild_lock); + pri_debug(LOG_NOTICE, "pri_reader_thread: time to " + "exit\n"); + break; + } + + /* + * Wait until the worker is idle before swapping in the + * new PRI contents, then signal the worker to process + * that new data. + */ + if (status == 0) { + pri_debug(LOG_NOTICE, "pri_reader_thread: got PRI\n"); + + /* old buffer will be freed by pri_bufinit() */ + mdp = pri_bufinit(mdp); + if (mdp != NULL) { + (void) cond_signal(&rebuild_cv); + count = 0; + } else { + pri_debug(LOG_NOTICE, "pri_reader_thread: " + "NULL mdp!\n"); + status = -1; + } + } + + /* + * Try to handle SP resets or other unexplained errors + * from ds by closing down and re-opening the PRI driver. + */ + if (status == -1) { + if (errno != 0) { + pri_debug(LOG_NOTICE, "pri_reader_thread: " + "can't get PRI contents: %s\n", + strerror(errno)); + } + if (++count > 6) { + pri_debug(LOG_NOTICE, "pci_reader_thread: " + "can't process PRI data\n"); + (void) mutex_unlock(&rebuild_lock); + break; + } + /* old buffer will be freed by pri_fini() */ + pri_fini(); + tok = 0; + sleep(10); + if (pri_init() != 0) { + pri_debug(LOG_NOTICE, "pci_reader_thread: " + "can't reinitialize PRI driver\n"); + (void) mutex_unlock(&rebuild_lock); + break; + } + } + (void) mutex_unlock(&rebuild_lock); } - for (tok = 0; mdp = pri_devinit(&tok, mdp); ) { - rootnode = md_root_node(mdp); - - pri_debug(LOG_NOTICE, "priplugin: have root picl and PRI " - "nodes\n"); - - status = ptree_walk_tree_by_class(root_node, "memory", - (void *) mdp, add_mem_prop); - if (status != PICL_SUCCESS) { - pri_debug(LOG_NOTICE, "pri: memory-segments walk " - "failed\n"); - } else - pri_debug(LOG_NOTICE, "pri: success walking memory " - "node\n"); - - io_dev_addlabel(mdp); - } - - pri_debug(LOG_NOTICE, "priplugin: cannot init pri: " "%d\n", errno); - - priplugin_fini(); - - /*NOTREACHED*/ + pri_debug(LOG_NOTICE, "pri_reader_thread: thread exiting\n"); return (NULL); } -void +static void priplugin_fini(void) { - pri_devfini(mdp); - /* unregister the event handler */ + pri_debug(LOG_NOTICE, "priplugin_fini: called\n"); + + if (all_thr_exit == B_TRUE) + return; + + /* unregister the event handlers */ (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, event_handler, NULL); + (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED, + event_handler, NULL); (void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE, event_handler, NULL); + + /* + * Set the exit flag to tell the worker thread to quit and wake + * up that thread. Once that thread is reaped then pull the rug + * out from the PRI reader thread by calling pri_fini(), which + * closes the PRI fd. That wakes the PRI reader thread and it + * will then exit as well. + */ + (void) mutex_lock(&rebuild_lock); + all_thr_exit = B_TRUE; + (void) cond_signal(&rebuild_cv); + (void) mutex_unlock(&rebuild_lock); + + (void) thr_join(pri_worker_thread_id, NULL, NULL); + + pri_devfini(mdp); + mdp = NULL; + pri_fini(); + (void) thr_join(pri_reader_thread_id, NULL, NULL); + + (void) mutex_destroy(&rebuild_lock); + (void) cond_destroy(&rebuild_cv); } void @@ -183,6 +368,7 @@ * Discovery event handler * respond to the picl events: * PICLEVENT_SYSEVENT_DEVICE_ADDED + * PICLEVENT_SYSEVENT_DEVICE_REMOVED * PICLEVENT_DR_AP_STATE_CHANGE * * We can't do much of anything fancy since the event data doesn't contain @@ -193,12 +379,19 @@ static void event_handler(const char *ename, const void *earg, size_t size, void *cookie) { - + pri_debug(LOG_NOTICE, "pri: event_handler: caught event " + "%s\n", ename); if ((strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) || + (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) || (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) == 0)) { - pri_debug(LOG_NOTICE, "pri: event_handler: caught event " - "%s; adding labels\n", ename); - io_dev_addlabel(mdp); + pri_debug(LOG_NOTICE, "pri: event_handler: handle event " + "%s; waking worker thread\n", ename); + (void) mutex_lock(&rebuild_lock); + + if (all_thr_exit == B_FALSE) + (void) cond_signal(&rebuild_cv); + + (void) mutex_unlock(&rebuild_lock); } }
--- a/usr/src/cmd/picl/plugins/sun4v/pri/priplugin.h Tue Sep 11 16:36:53 2007 -0700 +++ b/usr/src/cmd/picl/plugins/sun4v/pri/priplugin.h Tue Sep 11 16:39:42 2007 -0700 @@ -65,12 +65,9 @@ #define PRI_DEBUG 0 #endif -/* These 3 variable are defined and set in mdescplugin.c */ -extern picl_nodehdl_t root_node; -extern mde_cookie_t rootnode; - int add_mem_prop(picl_nodehdl_t node, void *args); -md_t *pri_devinit(uint64_t *, md_t *); +int pri_devinit(uint64_t *); +md_t *pri_bufinit(md_t *mdp); void pri_devfini(md_t *mdp); void pri_debug(int level, char *fmt, ...); void add_md_prop(picl_nodehdl_t node, int size, char *name, void* value,
--- a/usr/src/cmd/picl/plugins/sun4v/snmp/snmpplugin.c Tue Sep 11 16:36:53 2007 -0700 +++ b/usr/src/cmd/picl/plugins/sun4v/snmp/snmpplugin.c Tue Sep 11 16:39:42 2007 -0700 @@ -96,6 +96,8 @@ static mutex_t rebuild_tree_lock; static cond_t rebuild_tree_cv; static boolean_t rebuild_tree = B_TRUE; +static boolean_t tree_builder_thr_exit = B_FALSE; +static thread_t tree_builder_thr_id; /* * These two should really not be global @@ -270,6 +272,8 @@ (void) mutex_init(&rebuild_tree_lock, USYNC_THREAD, NULL); (void) cond_init(&rebuild_tree_cv, USYNC_THREAD, NULL); (void) rwlock_init(&stale_tree_rwlp, USYNC_THREAD, NULL); + tree_builder_thr_exit = B_FALSE; + LOGINIT(); /* @@ -277,18 +281,57 @@ */ LOGPRINTF("Tree-builder thread being created.\n"); if ((ret = thr_create(NULL, NULL, tree_builder, NULL, - THR_BOUND, NULL)) < 0) { + THR_BOUND, &tree_builder_thr_id)) < 0) { log_msg(LOG_ERR, SNMPP_CANT_CREATE_TREE_BUILDER, ret); snmp_fini(hdl); - return; + hdl = NULL; + (void) rwlock_destroy(&stale_tree_rwlp); + (void) cond_destroy(&rebuild_tree_cv); + (void) mutex_destroy(&rebuild_tree_lock); + tree_builder_thr_exit = B_TRUE; } } void snmpplugin_fini(void) { - snmp_fini(hdl); + + if (tree_builder_thr_exit == B_TRUE) + return; + /* + * Make reads of volatile properties return PICL_PROPUNAVAILABLE + * since we're about to recycle the plug-in. No need to worry + * about removing /physical-platform since tree_builder() will + * take care of recycling it for us. + */ + (void) rw_wrlock(&stale_tree_rwlp); + stale_tree = B_TRUE; + if (vol_props) { + free(vol_props); + } + vol_props = NULL; + volprop_ndx = 0; + n_vol_props = 0; + (void) rw_unlock(&stale_tree_rwlp); + + /* wake up the tree_builder thread, tell it to exit */ + (void) mutex_lock(&rebuild_tree_lock); + rebuild_tree = B_TRUE; + tree_builder_thr_exit = B_TRUE; + cond_signal(&rebuild_tree_cv); + (void) mutex_unlock(&rebuild_tree_lock); + + /* reap the thread */ + (void) thr_join(tree_builder_thr_id, NULL, NULL); + + /* close the channel */ + if (hdl != NULL) { + snmp_fini(hdl); + hdl = NULL; + } + + /* finish cleanup... */ (void) rwlock_destroy(&stale_tree_rwlp); (void) cond_destroy(&rebuild_tree_cv); (void) mutex_destroy(&rebuild_tree_lock); @@ -330,11 +373,18 @@ LOGPRINTF("tree_builder: woke up\n"); + if (tree_builder_thr_exit == B_TRUE) { + (void) mutex_unlock(&rebuild_tree_lock); + LOGPRINTF("tree_builder: time to exit\n"); + return (NULL); + } + old_physplat_root = NULL; physplat_root = NULL; LOGPRINTF("tree_builder: getting root node\n"); if ((ret = ptree_get_root(&root_node)) != PICL_SUCCESS) { + (void) mutex_unlock(&rebuild_tree_lock); log_msg(LOG_ERR, SNMPP_NO_ROOT, ret); return ((void *)-2); } @@ -346,8 +396,10 @@ LOGPRINTF("tree_builder: building physical-platform\n"); if ((ret = build_physplat(&physplat_root)) < 0) { + (void) mutex_unlock(&rebuild_tree_lock); log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret); snmp_fini(hdl); + hdl = NULL; return ((void *)-3); } @@ -359,9 +411,11 @@ LOGPRINTF("tree_builder: attaching new subtree\n"); if ((ret = ptree_add_node(root_node, physplat_root)) < 0) { + (void) mutex_unlock(&rebuild_tree_lock); free_resources(physplat_root); log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret); snmp_fini(hdl); + hdl = NULL; return ((void *)-4); }