17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*d9638e54Smws  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <fmd_alloc.h>
307c478bd9Sstevel@tonic-gate #include <fmd_subr.h>
317c478bd9Sstevel@tonic-gate #include <fmd_conf.h>
327c478bd9Sstevel@tonic-gate #include <fmd_error.h>
337c478bd9Sstevel@tonic-gate #include <fmd_string.h>
347c478bd9Sstevel@tonic-gate #include <fmd_idspace.h>
357c478bd9Sstevel@tonic-gate #include <fmd.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate static int
387c478bd9Sstevel@tonic-gate highbit(ulong_t i)
397c478bd9Sstevel@tonic-gate {
407c478bd9Sstevel@tonic-gate 	int h = 1;
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate 	if (i == 0)
437c478bd9Sstevel@tonic-gate 		return (0);
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #ifdef _LP64
467c478bd9Sstevel@tonic-gate 	if (i & 0xffffffff00000000ul) {
477c478bd9Sstevel@tonic-gate 		h += 32;
487c478bd9Sstevel@tonic-gate 		i >>= 32;
497c478bd9Sstevel@tonic-gate 	}
507c478bd9Sstevel@tonic-gate #endif
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 	if (i & 0xffff0000) {
537c478bd9Sstevel@tonic-gate 		h += 16;
547c478bd9Sstevel@tonic-gate 		i >>= 16;
557c478bd9Sstevel@tonic-gate 	}
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate 	if (i & 0xff00) {
587c478bd9Sstevel@tonic-gate 		h += 8;
597c478bd9Sstevel@tonic-gate 		i >>= 8;
607c478bd9Sstevel@tonic-gate 	}
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	if (i & 0xf0) {
637c478bd9Sstevel@tonic-gate 		h += 4;
647c478bd9Sstevel@tonic-gate 		i >>= 4;
657c478bd9Sstevel@tonic-gate 	}
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	if (i & 0xc) {
687c478bd9Sstevel@tonic-gate 		h += 2;
697c478bd9Sstevel@tonic-gate 		i >>= 2;
707c478bd9Sstevel@tonic-gate 	}
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	if (i & 0x2)
737c478bd9Sstevel@tonic-gate 		h += 1;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	return (h);
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate fmd_idspace_t *
797c478bd9Sstevel@tonic-gate fmd_idspace_create(const char *name, id_t min, id_t max)
807c478bd9Sstevel@tonic-gate {
817c478bd9Sstevel@tonic-gate 	fmd_idspace_t *ids = fmd_alloc(sizeof (fmd_idspace_t), FMD_SLEEP);
827c478bd9Sstevel@tonic-gate 	uint_t ids_avg, ids_max, hashlen, hashmax;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	/*
857c478bd9Sstevel@tonic-gate 	 * Dynamically size the hash table bucket array based on the desired
867c478bd9Sstevel@tonic-gate 	 * chain length.  We hash by indexing on the low-order bits.
877c478bd9Sstevel@tonic-gate 	 * Do not permit the hash bucket array to exceed a reasonable size.
887c478bd9Sstevel@tonic-gate 	 */
897c478bd9Sstevel@tonic-gate 	ASSERT(min >= 0 && max >= 0);
907c478bd9Sstevel@tonic-gate 	ASSERT(max >= min);
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	(void) fmd_conf_getprop(fmd.d_conf, "ids.avg", &ids_avg);
937c478bd9Sstevel@tonic-gate 	(void) fmd_conf_getprop(fmd.d_conf, "ids.max", &ids_max);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	hashmax = max - min + 1;
967c478bd9Sstevel@tonic-gate 	hashlen = 1 << highbit(hashmax / ids_avg);
977c478bd9Sstevel@tonic-gate 	if (hashlen > ids_max)
987c478bd9Sstevel@tonic-gate 		hashlen = ids_max;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	(void) strlcpy(ids->ids_name, name, sizeof (ids->ids_name));
1017c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&ids->ids_lock, NULL);
102*d9638e54Smws 	(void) pthread_cond_init(&ids->ids_cv, NULL);
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	ids->ids_hash = fmd_zalloc(sizeof (void *) * hashlen, FMD_SLEEP);
1057c478bd9Sstevel@tonic-gate 	ids->ids_hashlen = hashlen;
106*d9638e54Smws 	ids->ids_refs = 0;
1077c478bd9Sstevel@tonic-gate 	ids->ids_nextid = min - 1;
1087c478bd9Sstevel@tonic-gate 	ids->ids_minid = min;
1097c478bd9Sstevel@tonic-gate 	ids->ids_maxid = max;
1107c478bd9Sstevel@tonic-gate 	ids->ids_count = 0;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	return (ids);
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate void
1167c478bd9Sstevel@tonic-gate fmd_idspace_destroy(fmd_idspace_t *ids)
1177c478bd9Sstevel@tonic-gate {
1187c478bd9Sstevel@tonic-gate 	fmd_idelem_t *ide, *nde;
1197c478bd9Sstevel@tonic-gate 	uint_t i;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ids->ids_lock);
1227c478bd9Sstevel@tonic-gate 
123*d9638e54Smws 	while (ids->ids_refs != 0)
124*d9638e54Smws 		(void) pthread_cond_wait(&ids->ids_cv, &ids->ids_lock);
125*d9638e54Smws 
1267c478bd9Sstevel@tonic-gate 	for (i = 0; i < ids->ids_hashlen; i++) {
1277c478bd9Sstevel@tonic-gate 		for (ide = ids->ids_hash[i]; ide != NULL; ide = nde) {
1287c478bd9Sstevel@tonic-gate 			nde = ide->ide_next;
1297c478bd9Sstevel@tonic-gate 			fmd_free(ide, sizeof (fmd_idelem_t));
1307c478bd9Sstevel@tonic-gate 		}
1317c478bd9Sstevel@tonic-gate 	}
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	fmd_free(ids->ids_hash, sizeof (void *) * ids->ids_hashlen);
1347c478bd9Sstevel@tonic-gate 	fmd_free(ids, sizeof (fmd_idspace_t));
1357c478bd9Sstevel@tonic-gate }
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate void
138*d9638e54Smws fmd_idspace_apply(fmd_idspace_t *ids,
139*d9638e54Smws     void (*func)(fmd_idspace_t *, id_t, void *), void *arg)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	fmd_idelem_t *ide;
1427c478bd9Sstevel@tonic-gate 	id_t *ida, *idp;
1437c478bd9Sstevel@tonic-gate 	uint_t i, count;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ids->ids_lock);
1467c478bd9Sstevel@tonic-gate 	count = ids->ids_count;
1477c478bd9Sstevel@tonic-gate 	ida = idp = fmd_alloc(sizeof (id_t) * count, FMD_SLEEP);
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	for (i = 0; i < ids->ids_hashlen; i++) {
1507c478bd9Sstevel@tonic-gate 		for (ide = ids->ids_hash[i]; ide != NULL; ide = ide->ide_next)
1517c478bd9Sstevel@tonic-gate 			*idp++ = ide->ide_id;
1527c478bd9Sstevel@tonic-gate 	}
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	ASSERT(idp == ida + count);
1557c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&ids->ids_lock);
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++)
158*d9638e54Smws 		func(ids, ida[i], arg);
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	fmd_free(ida, sizeof (id_t) * count);
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate static fmd_idelem_t *
1647c478bd9Sstevel@tonic-gate fmd_idspace_lookup(fmd_idspace_t *ids, id_t id)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate 	fmd_idelem_t *ide;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ids->ids_lock));
1697c478bd9Sstevel@tonic-gate 	ide = ids->ids_hash[id & (ids->ids_hashlen - 1)];
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	for (; ide != NULL; ide = ide->ide_next) {
1727c478bd9Sstevel@tonic-gate 		if (ide->ide_id == id)
1737c478bd9Sstevel@tonic-gate 			break;
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	return (ide);
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate void *
1807c478bd9Sstevel@tonic-gate fmd_idspace_getspecific(fmd_idspace_t *ids, id_t id)
1817c478bd9Sstevel@tonic-gate {
1827c478bd9Sstevel@tonic-gate 	fmd_idelem_t *ide;
1837c478bd9Sstevel@tonic-gate 	void *data;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ids->ids_lock);
1867c478bd9Sstevel@tonic-gate 	ide = fmd_idspace_lookup(ids, id);
1877c478bd9Sstevel@tonic-gate 	data = ide ? ide->ide_data : NULL;
1887c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&ids->ids_lock);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	return (data);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate void
1947c478bd9Sstevel@tonic-gate fmd_idspace_setspecific(fmd_idspace_t *ids, id_t id, void *data)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate 	fmd_idelem_t *ide;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ids->ids_lock);
1997c478bd9Sstevel@tonic-gate 
200*d9638e54Smws 	while (ids->ids_refs != 0)
201*d9638e54Smws 		(void) pthread_cond_wait(&ids->ids_cv, &ids->ids_lock);
202*d9638e54Smws 
2037c478bd9Sstevel@tonic-gate 	if ((ide = fmd_idspace_lookup(ids, id)) == NULL) {
2047c478bd9Sstevel@tonic-gate 		fmd_panic("idspace %p (%s) does not contain id %ld",
2057c478bd9Sstevel@tonic-gate 		    (void *)ids, ids->ids_name, id);
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	ide->ide_data = data;
2097c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&ids->ids_lock);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate int
2137c478bd9Sstevel@tonic-gate fmd_idspace_contains(fmd_idspace_t *ids, id_t id)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate 	fmd_idelem_t *ide;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ids->ids_lock);
2187c478bd9Sstevel@tonic-gate 	ide = fmd_idspace_lookup(ids, id);
2197c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&ids->ids_lock);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	return (ide != NULL);
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate int
2257c478bd9Sstevel@tonic-gate fmd_idspace_valid(fmd_idspace_t *ids, id_t id)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	return (id >= ids->ids_minid && id <= ids->ids_maxid);
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate static id_t
2317c478bd9Sstevel@tonic-gate fmd_idspace_xalloc_locked(fmd_idspace_t *ids, id_t id, void *data)
2327c478bd9Sstevel@tonic-gate {
2337c478bd9Sstevel@tonic-gate 	fmd_idelem_t *ide;
2347c478bd9Sstevel@tonic-gate 	uint_t h;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	if (id < ids->ids_minid || id > ids->ids_maxid) {
2377c478bd9Sstevel@tonic-gate 		fmd_panic("%ld out of range [%ld .. %ld] for idspace %p (%s)\n",
2387c478bd9Sstevel@tonic-gate 		    id, ids->ids_minid, ids->ids_maxid,
2397c478bd9Sstevel@tonic-gate 		    (void *)ids, ids->ids_name);
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	if (fmd_idspace_lookup(ids, id) != NULL)
2437c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(EALREADY));
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	ide = fmd_alloc(sizeof (fmd_idelem_t), FMD_SLEEP);
2467c478bd9Sstevel@tonic-gate 	h = id & (ids->ids_hashlen - 1);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	ide->ide_next = ids->ids_hash[h];
2497c478bd9Sstevel@tonic-gate 	ide->ide_data = data;
2507c478bd9Sstevel@tonic-gate 	ide->ide_id = id;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	ids->ids_hash[h] = ide;
2537c478bd9Sstevel@tonic-gate 	ids->ids_count++;
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	return (id);
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate id_t
2597c478bd9Sstevel@tonic-gate fmd_idspace_xalloc(fmd_idspace_t *ids, id_t id, void *data)
2607c478bd9Sstevel@tonic-gate {
2617c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ids->ids_lock);
2627c478bd9Sstevel@tonic-gate 	id = fmd_idspace_xalloc_locked(ids, id, data);
2637c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&ids->ids_lock);
2647c478bd9Sstevel@tonic-gate 	return (id);
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate 
267*d9638e54Smws static id_t
268*d9638e54Smws fmd_idspace_alloc_locked(fmd_idspace_t *ids, void *data)
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate 	id_t id;
2717c478bd9Sstevel@tonic-gate 
272*d9638e54Smws 	ASSERT(MUTEX_HELD(&ids->ids_lock));
2737c478bd9Sstevel@tonic-gate 
274*d9638e54Smws 	if (ids->ids_count == ids->ids_maxid - ids->ids_minid + 1)
2757c478bd9Sstevel@tonic-gate 		return (fmd_set_errno(ENOSPC));
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	do {
2787c478bd9Sstevel@tonic-gate 		if (++ids->ids_nextid > ids->ids_maxid)
2797c478bd9Sstevel@tonic-gate 			ids->ids_nextid = ids->ids_minid;
2807c478bd9Sstevel@tonic-gate 		id = ids->ids_nextid;
2817c478bd9Sstevel@tonic-gate 	} while (fmd_idspace_xalloc_locked(ids, id, data) != id);
2827c478bd9Sstevel@tonic-gate 
283*d9638e54Smws 	return (id);
284*d9638e54Smws }
285*d9638e54Smws 
286*d9638e54Smws id_t
287*d9638e54Smws fmd_idspace_alloc(fmd_idspace_t *ids, void *data)
288*d9638e54Smws {
289*d9638e54Smws 	id_t id;
290*d9638e54Smws 
291*d9638e54Smws 	(void) pthread_mutex_lock(&ids->ids_lock);
292*d9638e54Smws 	id = fmd_idspace_alloc_locked(ids, data);
2937c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&ids->ids_lock);
294*d9638e54Smws 
295*d9638e54Smws 	return (id);
296*d9638e54Smws }
297*d9638e54Smws 
298*d9638e54Smws /*
299*d9638e54Smws  * For the moment, we use a simple but slow implementation: reset ids_nextid to
300*d9638e54Smws  * the minimum id and search in order from there.  If this becomes performance
301*d9638e54Smws  * sensitive we can maintain a freelist of the unallocated identifiers, etc.
302*d9638e54Smws  */
303*d9638e54Smws id_t
304*d9638e54Smws fmd_idspace_alloc_min(fmd_idspace_t *ids, void *data)
305*d9638e54Smws {
306*d9638e54Smws 	id_t id;
307*d9638e54Smws 
308*d9638e54Smws 	(void) pthread_mutex_lock(&ids->ids_lock);
309*d9638e54Smws 	ids->ids_nextid = ids->ids_minid - 1;
310*d9638e54Smws 	id = fmd_idspace_alloc_locked(ids, data);
311*d9638e54Smws 	(void) pthread_mutex_unlock(&ids->ids_lock);
312*d9638e54Smws 
3137c478bd9Sstevel@tonic-gate 	return (id);
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate void *
3177c478bd9Sstevel@tonic-gate fmd_idspace_free(fmd_idspace_t *ids, id_t id)
3187c478bd9Sstevel@tonic-gate {
3197c478bd9Sstevel@tonic-gate 	fmd_idelem_t *ide, **pp;
3207c478bd9Sstevel@tonic-gate 	void *data;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ids->ids_lock);
3237c478bd9Sstevel@tonic-gate 	pp = &ids->ids_hash[id & (ids->ids_hashlen - 1)];
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	for (ide = *pp; ide != NULL; ide = ide->ide_next) {
3267c478bd9Sstevel@tonic-gate 		if (ide->ide_id != id)
3277c478bd9Sstevel@tonic-gate 			pp = &ide->ide_next;
3287c478bd9Sstevel@tonic-gate 		else
3297c478bd9Sstevel@tonic-gate 			break;
3307c478bd9Sstevel@tonic-gate 	}
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	if (ide == NULL) {
3337c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&ids->ids_lock);
3347c478bd9Sstevel@tonic-gate 		return (NULL);
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	data = ide->ide_data;
3387c478bd9Sstevel@tonic-gate 	*pp = ide->ide_next;
3397c478bd9Sstevel@tonic-gate 	fmd_free(ide, sizeof (fmd_idelem_t));
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	ASSERT(ids->ids_count != 0);
3427c478bd9Sstevel@tonic-gate 	ids->ids_count--;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&ids->ids_lock);
3457c478bd9Sstevel@tonic-gate 	return (data);
3467c478bd9Sstevel@tonic-gate }
347*d9638e54Smws 
348*d9638e54Smws /*
349*d9638e54Smws  * Retrieve the id-specific data for the specified id and place a hold on the
350*d9638e54Smws  * id so that it cannot be or deleted until fmd_idspace_rele(ids, id) is
351*d9638e54Smws  * called.  For simplicity, we now use a single global reference count for all
352*d9638e54Smws  * holds.  If this feature needs to be used in a place where there is high
353*d9638e54Smws  * contention between holders and deleters, the implementation can be modified
354*d9638e54Smws  * to use either a per-hash-bucket or a per-id-element condition variable.
355*d9638e54Smws  */
356*d9638e54Smws void *
357*d9638e54Smws fmd_idspace_hold(fmd_idspace_t *ids, id_t id)
358*d9638e54Smws {
359*d9638e54Smws 	fmd_idelem_t *ide;
360*d9638e54Smws 	void *data = NULL;
361*d9638e54Smws 
362*d9638e54Smws 	(void) pthread_mutex_lock(&ids->ids_lock);
363*d9638e54Smws 
364*d9638e54Smws 	if ((ide = fmd_idspace_lookup(ids, id)) != NULL) {
365*d9638e54Smws 		ids->ids_refs++;
366*d9638e54Smws 		ASSERT(ids->ids_refs != 0);
367*d9638e54Smws 		data = ide->ide_data;
368*d9638e54Smws 		ASSERT(data != NULL);
369*d9638e54Smws 	}
370*d9638e54Smws 
371*d9638e54Smws 	(void) pthread_mutex_unlock(&ids->ids_lock);
372*d9638e54Smws 	return (data);
373*d9638e54Smws }
374*d9638e54Smws 
375*d9638e54Smws void
376*d9638e54Smws fmd_idspace_rele(fmd_idspace_t *ids, id_t id)
377*d9638e54Smws {
378*d9638e54Smws 	(void) pthread_mutex_lock(&ids->ids_lock);
379*d9638e54Smws 
380*d9638e54Smws 	ASSERT(fmd_idspace_lookup(ids, id) != NULL);
381*d9638e54Smws 	ASSERT(ids->ids_refs != 0);
382*d9638e54Smws 	ids->ids_refs--;
383*d9638e54Smws 
384*d9638e54Smws 	(void) pthread_cond_broadcast(&ids->ids_cv);
385*d9638e54Smws 	(void) pthread_mutex_unlock(&ids->ids_lock);
386*d9638e54Smws }
387