Пример #1
0
void
topo_pgroup_destroy_all(tnode_t *node)
{
	topo_hdl_t *thp = node->tn_hdl;
	topo_pgroup_t *pg;
	topo_proplist_t *pvl;
	topo_ipgroup_info_t *pip;

	topo_node_lock(node);
	while ((pg = topo_list_next(&node->tn_pgroups)) != NULL) {
		while ((pvl = topo_list_next(&pg->tpg_pvals)) != NULL) {
			topo_list_delete(&pg->tpg_pvals, pvl);
			topo_prop_rele(pvl->tp_pval);
			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
		}

		topo_list_delete(&node->tn_pgroups, pg);

		pip = pg->tpg_info;
		if (pip != NULL) {
			if (pip->tpi_name != NULL)
				topo_hdl_strfree(thp, (char *)pip->tpi_name);
			topo_hdl_free(thp, pip, sizeof (topo_pgroup_info_t));
		}

		topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
	}
	topo_node_unlock(node);
}
Пример #2
0
static int
pgroup_seterr(tnode_t *node, topo_pgroup_t *pg, topo_ipgroup_info_t *pip,
    int *err)
{
	topo_hdl_t *thp = node->tn_hdl;

	if (pip != NULL) {
		if (pip->tpi_name != NULL)
			topo_hdl_strfree(thp, (char *)pip->tpi_name);
		topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
	}

	topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
	*err = ETOPO_NOMEM;

	topo_node_unlock(node);

	return (-1);
}
Пример #3
0
void
topo_walk_fini(topo_walk_t *wp)
{
	if (wp == NULL)
		return;

	topo_node_rele(wp->tw_root);

	topo_hdl_free(wp->tw_thp, wp, sizeof (topo_walk_t));
}
Пример #4
0
void
topo_pgroup_destroy(tnode_t *node, const char *pname)
{
	topo_hdl_t *thp = node->tn_hdl;
	topo_pgroup_t *pg;
	topo_proplist_t *pvl;
	topo_ipgroup_info_t *pip;

	topo_node_lock(node);
	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
	    pg = topo_list_next(pg)) {
		if (strcmp(pg->tpg_info->tpi_name, pname) == 0) {
			break;
		}
	}

	if (pg == NULL) {
		topo_node_unlock(node);
		return;
	}

	while ((pvl = topo_list_next(&pg->tpg_list)) != NULL) {
		topo_list_delete(&pg->tpg_pvals, pvl);
		topo_prop_rele(pvl->tp_pval);
		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
	}

	topo_list_delete(&node->tn_pgroups, pg);
	topo_node_unlock(node);

	pip = pg->tpg_info;
	if (pip != NULL) {
		if (pip->tpi_name != NULL)
			topo_hdl_strfree(thp, (char *)pip->tpi_name);
		topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
	}

	topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
}
Пример #5
0
void
topo_file_unload(topo_hdl_t *thp, ttree_t *tp)
{
	topo_file_t *tfp = tp->tt_file;

	if (tfp == NULL)
		return;

	if (tfp->tf_fileinfo != NULL)
		tf_info_free(tfp->tf_mod, tfp->tf_fileinfo);

	topo_hdl_free(thp, tfp, sizeof (topo_file_t));
	tp->tt_file = NULL;
}
Пример #6
0
static void
propmethod_destroy(topo_hdl_t *thp, topo_propval_t *pv)
{
	topo_propmethod_t *pm;

	pm = pv->tp_method;
	if (pm != NULL) {
		if (pm->tpm_name != NULL)
			topo_hdl_strfree(thp, pm->tpm_name);
		if (pm->tpm_args != NULL)
			nvlist_free(pm->tpm_args);
		topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
		pv->tp_method = NULL;
	}
}
Пример #7
0
static topo_propval_t *
set_seterror(tnode_t *node, topo_proplist_t *pvl, int *errp, int err)
{
	topo_hdl_t *thp = node->tn_hdl;
	topo_propval_t *pv;

	if (pvl != NULL) {
		pv = pvl->tp_pval;
		topo_propval_destroy(pv);
		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
	}

	topo_node_unlock(node);
	*errp = err;

	return (NULL);
}
Пример #8
0
static void
topo_propval_destroy(topo_propval_t *pv)
{
	topo_hdl_t *thp;

	if (pv == NULL)
		return;

	thp = pv->tp_hdl;

	if (pv->tp_name != NULL)
		topo_hdl_strfree(thp, pv->tp_name);

	if (pv->tp_val != NULL)
		nvlist_free(pv->tp_val);

	propmethod_destroy(thp, pv);

	topo_hdl_free(thp, pv, sizeof (topo_propval_t));
}
Пример #9
0
static int
register_methoderror(tnode_t *node, topo_propmethod_t *pm, int *errp, int l,
    int err)
{
	topo_hdl_t *thp = node->tn_hdl;

	if (pm != NULL) {
		if (pm->tpm_name != NULL)
			topo_hdl_strfree(thp, pm->tpm_name);
		if (pm->tpm_args != NULL)
			nvlist_free(pm->tpm_args);
		topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
	}

	*errp = err;

	if (l != 0)
		topo_node_unlock(node);

	return (-1);
}
Пример #10
0
static void
print_pgroup(topo_hdl_t *thp, tnode_t *node, const char *pgn, char *dstab,
    char *nstab, int32_t version)
{
	int err;
	char buf[30];
	topo_pgroup_info_t *pgi = NULL;

	if (pgn == NULL)
		return;

	if (node != NULL && (dstab == NULL || nstab == NULL || version == -1)) {
		if ((pgi = topo_pgroup_info(node, pgn, &err)) != NULL) {
			dstab = (char *)topo_stability2name(pgi->tpi_datastab);
			nstab = (char *)topo_stability2name(pgi->tpi_namestab);
			version = pgi->tpi_version;
		}
	}

	if (dstab == NULL || nstab == NULL || version == -1) {
		(void) printf("  group: %-30s version: - stability: -/-\n",
		    pgn);
	} else if (!opt_V && strlen(pgn) > 30) {
		(void) snprintf(buf, 26, "%s", pgn);
		(void) snprintf(&buf[27], 4, "%s", DOTS);
		(void) printf("  group: %-30s version: %-3d stability: %s/%s\n",
		    buf, version, nstab, dstab);
	} else {
		(void) printf("  group: %-30s version: %-3d stability: %s/%s\n",
		    pgn, version, nstab, dstab);
	}

	if (pgi != NULL) {
		topo_hdl_strfree(thp, (char *)pgi->tpi_name);
		topo_hdl_free(thp, pgi, sizeof (topo_pgroup_info_t));
	}
}
Пример #11
0
void
topo_prop_method_unregister(tnode_t *node, const char *pgname,
    const char *pname)
{
	topo_propval_t *pv;
	topo_pgroup_t *pg;
	topo_proplist_t *pvl;
	topo_hdl_t *thp = node->tn_hdl;

	topo_node_lock(node);

	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
	    pg = topo_list_next(pg)) {
		if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
			break;
		}
	}

	if (pg == NULL) {
		topo_node_unlock(node);
		return;
	}

	for (pvl = topo_list_next(&pg->tpg_list); pvl != NULL;
	    pvl = topo_list_next(pvl)) {
		pv = pvl->tp_pval;
		if (strcmp(pv->tp_name, pname) == 0) {
			topo_list_delete(&pg->tpg_pvals, pvl);
			assert(pv->tp_refs == 1);
			topo_prop_rele(pv);
			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
			break;
		}
	}

	topo_node_unlock(node);
}
Пример #12
0
topo_pgroup_info_t *
topo_pgroup_info(tnode_t *node, const char *pgname, int *err)
{
	topo_hdl_t *thp = node->tn_hdl;
	topo_pgroup_t *pg;
	topo_ipgroup_info_t *pip;
	topo_pgroup_info_t *info;

	topo_node_lock(node);
	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
	    pg = topo_list_next(pg)) {
		if (strcmp(pgname, pg->tpg_info->tpi_name) == 0) {
			if ((info = topo_hdl_alloc(thp,
			    sizeof (topo_pgroup_info_t))) == NULL)
				return (NULL);

			pip = pg->tpg_info;
			if ((info->tpi_name =
			    topo_hdl_strdup(thp, pip->tpi_name)) == NULL) {
				*err = ETOPO_PROP_NOMEM;
				topo_hdl_free(thp, info,
				    sizeof (topo_pgroup_info_t));
				topo_node_unlock(node);
				return (NULL);
			}
			info->tpi_namestab = pip->tpi_namestab;
			info->tpi_datastab = pip->tpi_datastab;
			info->tpi_version = pip->tpi_version;
			topo_node_unlock(node);
			return (info);
		}
	}

	*err = ETOPO_PROP_NOENT;
	topo_node_unlock(node);
	return (NULL);
}
Пример #13
0
static int
topo_add_disk(topo_hdl_t *thp, tnode_t *node, diskmon_t *target_diskp)
{
	nvlist_t	*fmri = NULL;
	nvlist_t	*asru_fmri;
	nvlist_t	*fru_fmri;
	char		*devpath = NULL;
	char		*capacity = NULL;
	char		*firmrev = NULL;
	char		*serial = NULL;
	char		*manuf = NULL;
	char		*model = NULL;
	char		*cstr = NULL;
	char		*buf;
	char		*label;
	char		*p;
	uint64_t	ptr = 0;
	int		buflen;
	int		err;
	int		orig_cstr_len;
	dm_fru_t	*frup;
	diskmon_t	*diskp;

	/*
	 * Match this node to a disk in the configuration by looking at
	 * our parent's fmri (and do that by getting our FMRI and chopping
	 * off the last part).
	 */
	if (topo_node_resource(node, &fmri, &err) != 0) {
		log_msg(MM_TOPO, "topo_add_disk: Could not generate FMRI for "
		    "node %p!\n", (void *)node);
		return (-1);
	}

	if (topo_fmri_nvl2str(thp, fmri, &cstr, &err) != 0) {
		log_msg(MM_TOPO, "topo_add_disk: Could not create string for "
		    "node %p's FMRI!\n", (void *)node);
		nvlist_free(fmri);
		return (-1);
	}

	nvlist_free(fmri);

	/*
	 * Chop off all but last path (since there's no way to get
	 * the node's parent in the libtopo API).
	 */
	orig_cstr_len = strlen(cstr) + 1;
	p = strrchr(cstr, '/');
	dm_assert(p != NULL);
	*p = 0;
	if (nvlist_lookup_uint64(g_topo2diskmon, cstr, &ptr) != 0) {
		log_msg(MM_TOPO, "No diskmon for parent of node %p.\n", node);
		topo_hdl_free(thp, cstr, orig_cstr_len);
		/* Skip this disk: */
		return (0);
	}

	topo_hdl_free(thp, cstr, orig_cstr_len);

	diskp = (diskmon_t *)(uintptr_t)ptr;

	/* If we were called upon to update a particular disk, do it */
	if (target_diskp != NULL && diskp != target_diskp) {
		return (0);
	}

	/*
	 * Update the diskmon's ASRU and FRU with our information (this
	 * information is cached in the diskmon so we don't have to do a
	 * time-consuming topo traversal when we get an ereport).
	 */
	if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU,
	    &asru_fmri, &err) == 0) {
		diskmon_add_asru(diskp, asru_fmri);
		nvlist_free(asru_fmri);
	}
	if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU,
	    &fru_fmri, &err) == 0) {
		diskmon_add_fru(diskp, fru_fmri);
		nvlist_free(fru_fmri);
	}
	if (topo_node_resource(node, &fmri, &err) == 0) {
		diskmon_add_disk_fmri(diskp, fmri);
		nvlist_free(fmri);
	}

	/*
	 * Update the diskmon's location field with the disk's label
	 */
	if (diskp->location)
		dstrfree(diskp->location);
	if (topo_node_label(node, &label, &err) == 0) {
		diskp->location = dstrdup(label);
		topo_hdl_strfree(thp, label);
	} else
		diskp->location = dstrdup("unknown location");

	/*
	 * Check for a device path property (if the disk is configured,
	 * it will be present) and add it to the diskmon's properties)
	 */
	if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV_PATH,
	    &devpath, &err) == 0) {
		char devp[PATH_MAX];
		/*
		 * Consumers of the DISK_PROP_DEVPATH property expect a raw
		 * minor device node
		 */
		(void) snprintf(devp, PATH_MAX, "%s:q,raw", devpath);
		(void) nvlist_add_string(diskp->props, DISK_PROP_DEVPATH,
		    devp);
		topo_hdl_strfree(thp, devpath);
	}

	/*
	 * Add the logical disk node, if it exists
	 */
	if (topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_LOGICAL_DISK_NAME, &devpath, &err) == 0) {
		(void) nvlist_add_string(diskp->props, DISK_PROP_LOGNAME,
		    devpath);
		topo_hdl_strfree(thp, devpath);
	}

	/*
	 * Add the FRU information (if present in the node) to the diskmon's
	 * fru data structure:
	 */
	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_MODEL, &model, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_MANUFACTURER, &manuf, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_SERIAL_NUM, &serial, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_FIRMWARE_REV, &firmrev, &err);

	(void) topo_prop_get_string(node, TOPO_STORAGE_PGROUP,
	    TOPO_STORAGE_CAPACITY, &capacity, &err);

	frup = new_dmfru(manuf, model, firmrev, serial,
	    capacity == NULL ? 0 : strtoull(capacity, 0, 0));

	/*
	 * Update the disk's resource FMRI with the
	 * SunService-required members:
	 * FM_FMRI_HC_SERIAL_ID, FM_FMRI_HC_PART, and
	 * FM_FMRI_HC_REVISION
	 */
	(void) nvlist_add_string(diskp->disk_res_fmri,
	    FM_FMRI_HC_SERIAL_ID, serial);

	transform_model_string(manuf, model, &buf, &buflen);

	(void) nvlist_add_string(diskp->disk_res_fmri,
	    FM_FMRI_HC_PART, buf);

	/*
	 * Add the serial number to the ASRU so that when the resource
	 * is marked faulty in the fmd resource cache, the hc scheme
	 * plugin can detect when the disk is no longer installed (and so,
	 * can clear the faulty state automatically across fmd restarts).
	 *
	 * The serial number is only updated when a disk comes online
	 * because that's when the disk node exists in the topo tree.
	 * It's ok to keep a stale value in the ASRU when the disk is removed
	 * because it's only used as part of fault creation when the disk
	 * is configured (online), at which point it will be updated with
	 * the (current) serial number of the disk inserted.
	 */
	(void) nvlist_add_string(diskp->asru_fmri,
	    FM_FMRI_HC_SERIAL_ID, serial);

	dfree(buf, buflen);

	(void) nvlist_add_string(diskp->disk_res_fmri,
	    FM_FMRI_HC_REVISION, firmrev);

	if (model) {
		topo_hdl_strfree(thp, model);
	}

	if (manuf) {
		topo_hdl_strfree(thp, manuf);
	}

	if (serial) {
		topo_hdl_strfree(thp, serial);
	}

	if (firmrev) {
		topo_hdl_strfree(thp, firmrev);
	}

	if (capacity) {
		topo_hdl_strfree(thp, capacity);
	}

	/* Add the fru information to the diskmon: */
	dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
	dm_assert(diskp->frup == NULL);
	diskp->frup = frup;
	dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);

	return (0);
}
Пример #14
0
static int
prop_getval(tnode_t *node, const char *pgname, const char *pname, void *val,
    topo_type_t type, uint_t *nelems, int *err)
{
	int i, j, ret = 0;
	topo_hdl_t *thp = node->tn_hdl;
	topo_propval_t *pv;

	topo_node_lock(node);
	if ((pv = prop_get(node, pgname, pname, NULL, err))
	    == NULL)
		return (get_properror(node, err, *err));

	if (pv->tp_type != type)
		return (get_properror(node, err, ETOPO_PROP_TYPE));

	switch (type) {
		case TOPO_TYPE_INT32:
			ret = nvlist_lookup_int32(pv->tp_val, TOPO_PROP_VAL_VAL,
			    (int32_t *)val);
			break;
		case TOPO_TYPE_UINT32:
			ret = nvlist_lookup_uint32(pv->tp_val,
			    TOPO_PROP_VAL_VAL, (uint32_t *)val);
			break;
		case TOPO_TYPE_INT64:
			ret = nvlist_lookup_int64(pv->tp_val, TOPO_PROP_VAL_VAL,
			    (int64_t *)val);
			break;
		case TOPO_TYPE_UINT64:
			ret = nvlist_lookup_uint64(pv->tp_val,
			    TOPO_PROP_VAL_VAL, (uint64_t *)val);
			break;
		case TOPO_TYPE_DOUBLE:
			ret = nvlist_lookup_double(pv->tp_val,
			    TOPO_PROP_VAL_VAL, (double *)val);
			break;
		case TOPO_TYPE_STRING: {
			char *str;

			ret = nvlist_lookup_string(pv->tp_val,
			    TOPO_PROP_VAL_VAL, &str);
			if (ret == 0) {
				char *s2;
				if ((s2 = topo_hdl_strdup(thp, str)) == NULL)
					ret = -1;
				else
					*(char **)val = s2;
			}
			break;
		}
		case TOPO_TYPE_FMRI: {
			nvlist_t *nvl;

			ret = nvlist_lookup_nvlist(pv->tp_val,
			    TOPO_PROP_VAL_VAL, &nvl);
			if (ret == 0)
				ret = topo_hdl_nvdup(thp, nvl,
				    (nvlist_t **)val);
			break;
		}
		case TOPO_TYPE_INT32_ARRAY: {
			int32_t *a1, *a2;

			if ((ret = nvlist_lookup_int32_array(pv->tp_val,
			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
				break;
			if ((a1 = topo_hdl_alloc(thp, sizeof (int32_t) *
			    *nelems)) == NULL) {
				ret = ETOPO_NOMEM;
				break;
			}
			for (i = 0; i < *nelems; ++i)
				a1[i] = a2[i];
			*(int32_t **)val = a1;
			break;
		}
		case TOPO_TYPE_UINT32_ARRAY: {
			uint32_t *a1, *a2;

			if ((ret = nvlist_lookup_uint32_array(pv->tp_val,
			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
				break;
			if ((a1 = topo_hdl_alloc(thp, sizeof (uint32_t) *
			    *nelems)) == NULL) {
				ret = ETOPO_NOMEM;
				break;
			}
			for (i = 0; i < *nelems; ++i)
				a1[i] = a2[i];
			*(uint32_t **)val = a1;
			break;
		}
		case TOPO_TYPE_INT64_ARRAY: {
			int64_t *a1, *a2;

			if ((ret = nvlist_lookup_int64_array(pv->tp_val,
			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
				break;
			if ((a1 = topo_hdl_alloc(thp, sizeof (int64_t) *
			    *nelems)) == NULL) {
				ret = ETOPO_NOMEM;
				break;
			}
			for (i = 0; i < *nelems; ++i)
				a1[i] = a2[i];
			*(int64_t **)val = a1;
			break;
		}
		case TOPO_TYPE_UINT64_ARRAY: {
			uint64_t *a1, *a2;

			if ((ret = nvlist_lookup_uint64_array(pv->tp_val,
			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
				break;
			if ((a1 = topo_hdl_alloc(thp, sizeof (uint64_t) *
			    *nelems)) == NULL) {
				ret = ETOPO_NOMEM;
				break;
			}
			for (i = 0; i < *nelems; ++i)
				a1[i] = a2[i];
			*(uint64_t **)val = a1;
			break;
		}
		case TOPO_TYPE_STRING_ARRAY: {
			char **a1, **a2;

			if ((ret = nvlist_lookup_string_array(pv->tp_val,
			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
				break;
			if ((a1 = topo_hdl_alloc(thp, sizeof (char *) *
			    *nelems)) == NULL) {
				ret = ETOPO_NOMEM;
				break;
			}
			for (i = 0; i < *nelems; ++i) {
				if ((a1[i] = topo_hdl_strdup(thp, a2[i]))
				    == NULL) {
					for (j = 0; j < i; ++j)
						topo_hdl_free(thp, a1[j],
						    sizeof (char *));
					topo_hdl_free(thp, a1,
					    sizeof (char *) * *nelems);
					break;
				}
			}
			*(char ***)val = a1;
			break;
		}
		case TOPO_TYPE_FMRI_ARRAY: {
			nvlist_t **a1, **a2;

			if ((ret = nvlist_lookup_nvlist_array(pv->tp_val,
			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
				break;
			if ((a1 = topo_hdl_alloc(thp, sizeof (nvlist_t *) *
			    *nelems)) == NULL) {
				ret = ETOPO_NOMEM;
				break;
			}
			for (i = 0; i < *nelems; ++i) {
				if (topo_hdl_nvdup(thp, a2[i], &a1[i]) < 0) {
					for (j = 0; j < i; ++j)
						nvlist_free(a1[j]);
					topo_hdl_free(thp, a1,
					    sizeof (nvlist_t *) * *nelems);
					break;
				}
			}
			*(nvlist_t ***)val = a1;
			break;
		}
		default:
			ret = ETOPO_PROP_NOENT;
	}

	if (ret != 0)
		if (ret == ENOENT)
			return (get_properror(node, err, ETOPO_PROP_NOENT));
		else if (ret < ETOPO_UNKNOWN)
			return (get_properror(node, err, ETOPO_PROP_NVL));
		else
			return (get_properror(node, err, ret));

	topo_node_unlock(node);
	return (0);
}
Пример #15
0
static void
topo_snap_destroy(topo_hdl_t *thp)
{
	int i;
	ttree_t *tp;
	topo_walk_t *twp;
	tnode_t *root;
	topo_nodehash_t *nhp;
	topo_mod_t *mod;

	for (tp = topo_list_next(&thp->th_trees); tp != NULL;
	    tp = topo_list_next(tp)) {

		root = tp->tt_root;
		twp = tp->tt_walk;
		/*
		 * Clean-up tree nodes from the bottom-up
		 */
		if ((twp->tw_node = topo_child_first(root)) != NULL) {
			twp->tw_cb = topo_walk_destroy;
			topo_node_hold(root);
			topo_node_hold(twp->tw_node); /* released at walk end */
			(void) topo_walk_bottomup(twp, TOPO_WALK_CHILD);
			topo_node_rele(root);
		}

		/*
		 * Tidy-up the root node
		 */
		while ((nhp = topo_list_next(&root->tn_children)) != NULL) {
			for (i = 0; i < nhp->th_arrlen; i++) {
				assert(nhp->th_nodearr[i] == NULL);
			}
			mod = nhp->th_enum;
			topo_mod_strfree(mod, nhp->th_name);
			topo_mod_free(mod, nhp->th_nodearr,
			    nhp->th_arrlen * sizeof (tnode_t *));
			topo_list_delete(&root->tn_children, nhp);
			topo_mod_free(mod, nhp, sizeof (topo_nodehash_t));
			topo_mod_rele(mod);
		}

	}

	/*
	 * Clean-up our cached devinfo and prom tree handles.
	 */
	if (thp->th_di != DI_NODE_NIL) {
		di_fini(thp->th_di);
		thp->th_di = DI_NODE_NIL;
	}
	if (thp->th_pi != DI_PROM_HANDLE_NIL) {
		di_prom_fini(thp->th_pi);
		thp->th_pi = DI_PROM_HANDLE_NIL;
	}


	if (thp->th_uuid != NULL) {
		topo_hdl_free(thp, thp->th_uuid, TOPO_UUID_SIZE);
		thp->th_uuid = NULL;
	}
}