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
5*23a1cceaSRoger A. Faulkner * Common Development and Distribution License (the "License").
6*23a1cceaSRoger A. Faulkner * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate
22*23a1cceaSRoger A. Faulkner /*
23*23a1cceaSRoger A. Faulkner * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24*23a1cceaSRoger A. Faulkner */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #include <fmd_alloc.h>
277c478bd9Sstevel@tonic-gate #include <fmd_subr.h>
287c478bd9Sstevel@tonic-gate #include <fmd_conf.h>
297c478bd9Sstevel@tonic-gate #include <fmd_error.h>
307c478bd9Sstevel@tonic-gate #include <fmd_string.h>
317c478bd9Sstevel@tonic-gate #include <fmd_idspace.h>
327c478bd9Sstevel@tonic-gate #include <fmd.h>
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gate fmd_idspace_t *
fmd_idspace_create(const char * name,id_t min,id_t max)357c478bd9Sstevel@tonic-gate fmd_idspace_create(const char *name, id_t min, id_t max)
367c478bd9Sstevel@tonic-gate {
377c478bd9Sstevel@tonic-gate fmd_idspace_t *ids = fmd_alloc(sizeof (fmd_idspace_t), FMD_SLEEP);
387c478bd9Sstevel@tonic-gate uint_t ids_avg, ids_max, hashlen, hashmax;
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate * Dynamically size the hash table bucket array based on the desired
427c478bd9Sstevel@tonic-gate * chain length. We hash by indexing on the low-order bits.
437c478bd9Sstevel@tonic-gate * Do not permit the hash bucket array to exceed a reasonable size.
447c478bd9Sstevel@tonic-gate */
457c478bd9Sstevel@tonic-gate ASSERT(min >= 0 && max >= 0);
467c478bd9Sstevel@tonic-gate ASSERT(max >= min);
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "ids.avg", &ids_avg);
497c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "ids.max", &ids_max);
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate hashmax = max - min + 1;
52*23a1cceaSRoger A. Faulkner hashlen = 1 << fls(hashmax / ids_avg);
537c478bd9Sstevel@tonic-gate if (hashlen > ids_max)
547c478bd9Sstevel@tonic-gate hashlen = ids_max;
557c478bd9Sstevel@tonic-gate
567c478bd9Sstevel@tonic-gate (void) strlcpy(ids->ids_name, name, sizeof (ids->ids_name));
577c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&ids->ids_lock, NULL);
58d9638e54Smws (void) pthread_cond_init(&ids->ids_cv, NULL);
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gate ids->ids_hash = fmd_zalloc(sizeof (void *) * hashlen, FMD_SLEEP);
617c478bd9Sstevel@tonic-gate ids->ids_hashlen = hashlen;
62d9638e54Smws ids->ids_refs = 0;
637c478bd9Sstevel@tonic-gate ids->ids_nextid = min - 1;
647c478bd9Sstevel@tonic-gate ids->ids_minid = min;
657c478bd9Sstevel@tonic-gate ids->ids_maxid = max;
667c478bd9Sstevel@tonic-gate ids->ids_count = 0;
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate return (ids);
697c478bd9Sstevel@tonic-gate }
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate void
fmd_idspace_destroy(fmd_idspace_t * ids)727c478bd9Sstevel@tonic-gate fmd_idspace_destroy(fmd_idspace_t *ids)
737c478bd9Sstevel@tonic-gate {
747c478bd9Sstevel@tonic-gate fmd_idelem_t *ide, *nde;
757c478bd9Sstevel@tonic-gate uint_t i;
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ids->ids_lock);
787c478bd9Sstevel@tonic-gate
79d9638e54Smws while (ids->ids_refs != 0)
80d9638e54Smws (void) pthread_cond_wait(&ids->ids_cv, &ids->ids_lock);
81d9638e54Smws
827c478bd9Sstevel@tonic-gate for (i = 0; i < ids->ids_hashlen; i++) {
837c478bd9Sstevel@tonic-gate for (ide = ids->ids_hash[i]; ide != NULL; ide = nde) {
847c478bd9Sstevel@tonic-gate nde = ide->ide_next;
857c478bd9Sstevel@tonic-gate fmd_free(ide, sizeof (fmd_idelem_t));
867c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate fmd_free(ids->ids_hash, sizeof (void *) * ids->ids_hashlen);
907c478bd9Sstevel@tonic-gate fmd_free(ids, sizeof (fmd_idspace_t));
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate void
fmd_idspace_apply(fmd_idspace_t * ids,void (* func)(fmd_idspace_t *,id_t,void *),void * arg)94d9638e54Smws fmd_idspace_apply(fmd_idspace_t *ids,
95d9638e54Smws void (*func)(fmd_idspace_t *, id_t, void *), void *arg)
967c478bd9Sstevel@tonic-gate {
977c478bd9Sstevel@tonic-gate fmd_idelem_t *ide;
987c478bd9Sstevel@tonic-gate id_t *ida, *idp;
997c478bd9Sstevel@tonic-gate uint_t i, count;
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ids->ids_lock);
1027c478bd9Sstevel@tonic-gate count = ids->ids_count;
1037c478bd9Sstevel@tonic-gate ida = idp = fmd_alloc(sizeof (id_t) * count, FMD_SLEEP);
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate for (i = 0; i < ids->ids_hashlen; i++) {
1067c478bd9Sstevel@tonic-gate for (ide = ids->ids_hash[i]; ide != NULL; ide = ide->ide_next)
1077c478bd9Sstevel@tonic-gate *idp++ = ide->ide_id;
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate ASSERT(idp == ida + count);
1117c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ids->ids_lock);
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate for (i = 0; i < count; i++)
114d9638e54Smws func(ids, ida[i], arg);
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate fmd_free(ida, sizeof (id_t) * count);
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate static fmd_idelem_t *
fmd_idspace_lookup(fmd_idspace_t * ids,id_t id)1207c478bd9Sstevel@tonic-gate fmd_idspace_lookup(fmd_idspace_t *ids, id_t id)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate fmd_idelem_t *ide;
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ids->ids_lock));
1257c478bd9Sstevel@tonic-gate ide = ids->ids_hash[id & (ids->ids_hashlen - 1)];
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate for (; ide != NULL; ide = ide->ide_next) {
1287c478bd9Sstevel@tonic-gate if (ide->ide_id == id)
1297c478bd9Sstevel@tonic-gate break;
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate return (ide);
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate void *
fmd_idspace_getspecific(fmd_idspace_t * ids,id_t id)1367c478bd9Sstevel@tonic-gate fmd_idspace_getspecific(fmd_idspace_t *ids, id_t id)
1377c478bd9Sstevel@tonic-gate {
1387c478bd9Sstevel@tonic-gate fmd_idelem_t *ide;
1397c478bd9Sstevel@tonic-gate void *data;
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ids->ids_lock);
1427c478bd9Sstevel@tonic-gate ide = fmd_idspace_lookup(ids, id);
1437c478bd9Sstevel@tonic-gate data = ide ? ide->ide_data : NULL;
1447c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ids->ids_lock);
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate return (data);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate void
fmd_idspace_setspecific(fmd_idspace_t * ids,id_t id,void * data)1507c478bd9Sstevel@tonic-gate fmd_idspace_setspecific(fmd_idspace_t *ids, id_t id, void *data)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate fmd_idelem_t *ide;
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ids->ids_lock);
1557c478bd9Sstevel@tonic-gate
156d9638e54Smws while (ids->ids_refs != 0)
157d9638e54Smws (void) pthread_cond_wait(&ids->ids_cv, &ids->ids_lock);
158d9638e54Smws
1597c478bd9Sstevel@tonic-gate if ((ide = fmd_idspace_lookup(ids, id)) == NULL) {
1607c478bd9Sstevel@tonic-gate fmd_panic("idspace %p (%s) does not contain id %ld",
1617c478bd9Sstevel@tonic-gate (void *)ids, ids->ids_name, id);
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate ide->ide_data = data;
1657c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ids->ids_lock);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate int
fmd_idspace_contains(fmd_idspace_t * ids,id_t id)1697c478bd9Sstevel@tonic-gate fmd_idspace_contains(fmd_idspace_t *ids, id_t id)
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate fmd_idelem_t *ide;
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ids->ids_lock);
1747c478bd9Sstevel@tonic-gate ide = fmd_idspace_lookup(ids, id);
1757c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ids->ids_lock);
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate return (ide != NULL);
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate int
fmd_idspace_valid(fmd_idspace_t * ids,id_t id)1817c478bd9Sstevel@tonic-gate fmd_idspace_valid(fmd_idspace_t *ids, id_t id)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate return (id >= ids->ids_minid && id <= ids->ids_maxid);
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate
1867c478bd9Sstevel@tonic-gate static id_t
fmd_idspace_xalloc_locked(fmd_idspace_t * ids,id_t id,void * data)1877c478bd9Sstevel@tonic-gate fmd_idspace_xalloc_locked(fmd_idspace_t *ids, id_t id, void *data)
1887c478bd9Sstevel@tonic-gate {
1897c478bd9Sstevel@tonic-gate fmd_idelem_t *ide;
1907c478bd9Sstevel@tonic-gate uint_t h;
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate if (id < ids->ids_minid || id > ids->ids_maxid) {
1937c478bd9Sstevel@tonic-gate fmd_panic("%ld out of range [%ld .. %ld] for idspace %p (%s)\n",
1947c478bd9Sstevel@tonic-gate id, ids->ids_minid, ids->ids_maxid,
1957c478bd9Sstevel@tonic-gate (void *)ids, ids->ids_name);
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate if (fmd_idspace_lookup(ids, id) != NULL)
1997c478bd9Sstevel@tonic-gate return (fmd_set_errno(EALREADY));
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate ide = fmd_alloc(sizeof (fmd_idelem_t), FMD_SLEEP);
2027c478bd9Sstevel@tonic-gate h = id & (ids->ids_hashlen - 1);
2037c478bd9Sstevel@tonic-gate
2047c478bd9Sstevel@tonic-gate ide->ide_next = ids->ids_hash[h];
2057c478bd9Sstevel@tonic-gate ide->ide_data = data;
2067c478bd9Sstevel@tonic-gate ide->ide_id = id;
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate ids->ids_hash[h] = ide;
2097c478bd9Sstevel@tonic-gate ids->ids_count++;
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate return (id);
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate id_t
fmd_idspace_xalloc(fmd_idspace_t * ids,id_t id,void * data)2157c478bd9Sstevel@tonic-gate fmd_idspace_xalloc(fmd_idspace_t *ids, id_t id, void *data)
2167c478bd9Sstevel@tonic-gate {
2177c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ids->ids_lock);
2187c478bd9Sstevel@tonic-gate id = fmd_idspace_xalloc_locked(ids, id, data);
2197c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ids->ids_lock);
2207c478bd9Sstevel@tonic-gate return (id);
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate
223d9638e54Smws static id_t
fmd_idspace_alloc_locked(fmd_idspace_t * ids,void * data)224d9638e54Smws fmd_idspace_alloc_locked(fmd_idspace_t *ids, void *data)
2257c478bd9Sstevel@tonic-gate {
2267c478bd9Sstevel@tonic-gate id_t id;
2277c478bd9Sstevel@tonic-gate
228d9638e54Smws ASSERT(MUTEX_HELD(&ids->ids_lock));
2297c478bd9Sstevel@tonic-gate
230d9638e54Smws if (ids->ids_count == ids->ids_maxid - ids->ids_minid + 1)
2317c478bd9Sstevel@tonic-gate return (fmd_set_errno(ENOSPC));
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate do {
2347c478bd9Sstevel@tonic-gate if (++ids->ids_nextid > ids->ids_maxid)
2357c478bd9Sstevel@tonic-gate ids->ids_nextid = ids->ids_minid;
2367c478bd9Sstevel@tonic-gate id = ids->ids_nextid;
2377c478bd9Sstevel@tonic-gate } while (fmd_idspace_xalloc_locked(ids, id, data) != id);
2387c478bd9Sstevel@tonic-gate
239d9638e54Smws return (id);
240d9638e54Smws }
241d9638e54Smws
242d9638e54Smws id_t
fmd_idspace_alloc(fmd_idspace_t * ids,void * data)243d9638e54Smws fmd_idspace_alloc(fmd_idspace_t *ids, void *data)
244d9638e54Smws {
245d9638e54Smws id_t id;
246d9638e54Smws
247d9638e54Smws (void) pthread_mutex_lock(&ids->ids_lock);
248d9638e54Smws id = fmd_idspace_alloc_locked(ids, data);
2497c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ids->ids_lock);
250d9638e54Smws
251d9638e54Smws return (id);
252d9638e54Smws }
253d9638e54Smws
254d9638e54Smws /*
255d9638e54Smws * For the moment, we use a simple but slow implementation: reset ids_nextid to
256d9638e54Smws * the minimum id and search in order from there. If this becomes performance
257d9638e54Smws * sensitive we can maintain a freelist of the unallocated identifiers, etc.
258d9638e54Smws */
259d9638e54Smws id_t
fmd_idspace_alloc_min(fmd_idspace_t * ids,void * data)260d9638e54Smws fmd_idspace_alloc_min(fmd_idspace_t *ids, void *data)
261d9638e54Smws {
262d9638e54Smws id_t id;
263d9638e54Smws
264d9638e54Smws (void) pthread_mutex_lock(&ids->ids_lock);
265d9638e54Smws ids->ids_nextid = ids->ids_minid - 1;
266d9638e54Smws id = fmd_idspace_alloc_locked(ids, data);
267d9638e54Smws (void) pthread_mutex_unlock(&ids->ids_lock);
268d9638e54Smws
2697c478bd9Sstevel@tonic-gate return (id);
2707c478bd9Sstevel@tonic-gate }
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate void *
fmd_idspace_free(fmd_idspace_t * ids,id_t id)2737c478bd9Sstevel@tonic-gate fmd_idspace_free(fmd_idspace_t *ids, id_t id)
2747c478bd9Sstevel@tonic-gate {
2757c478bd9Sstevel@tonic-gate fmd_idelem_t *ide, **pp;
2767c478bd9Sstevel@tonic-gate void *data;
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ids->ids_lock);
2797c478bd9Sstevel@tonic-gate pp = &ids->ids_hash[id & (ids->ids_hashlen - 1)];
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate for (ide = *pp; ide != NULL; ide = ide->ide_next) {
2827c478bd9Sstevel@tonic-gate if (ide->ide_id != id)
2837c478bd9Sstevel@tonic-gate pp = &ide->ide_next;
2847c478bd9Sstevel@tonic-gate else
2857c478bd9Sstevel@tonic-gate break;
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate if (ide == NULL) {
2897c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ids->ids_lock);
2907c478bd9Sstevel@tonic-gate return (NULL);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate data = ide->ide_data;
2947c478bd9Sstevel@tonic-gate *pp = ide->ide_next;
2957c478bd9Sstevel@tonic-gate fmd_free(ide, sizeof (fmd_idelem_t));
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate ASSERT(ids->ids_count != 0);
2987c478bd9Sstevel@tonic-gate ids->ids_count--;
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ids->ids_lock);
3017c478bd9Sstevel@tonic-gate return (data);
3027c478bd9Sstevel@tonic-gate }
303d9638e54Smws
304d9638e54Smws /*
305d9638e54Smws * Retrieve the id-specific data for the specified id and place a hold on the
306d9638e54Smws * id so that it cannot be or deleted until fmd_idspace_rele(ids, id) is
307d9638e54Smws * called. For simplicity, we now use a single global reference count for all
308d9638e54Smws * holds. If this feature needs to be used in a place where there is high
309d9638e54Smws * contention between holders and deleters, the implementation can be modified
310d9638e54Smws * to use either a per-hash-bucket or a per-id-element condition variable.
311d9638e54Smws */
312d9638e54Smws void *
fmd_idspace_hold(fmd_idspace_t * ids,id_t id)313d9638e54Smws fmd_idspace_hold(fmd_idspace_t *ids, id_t id)
314d9638e54Smws {
315d9638e54Smws fmd_idelem_t *ide;
316d9638e54Smws void *data = NULL;
317d9638e54Smws
318d9638e54Smws (void) pthread_mutex_lock(&ids->ids_lock);
319d9638e54Smws
320d9638e54Smws if ((ide = fmd_idspace_lookup(ids, id)) != NULL) {
321d9638e54Smws ids->ids_refs++;
322d9638e54Smws ASSERT(ids->ids_refs != 0);
323d9638e54Smws data = ide->ide_data;
324d9638e54Smws ASSERT(data != NULL);
325d9638e54Smws }
326d9638e54Smws
327d9638e54Smws (void) pthread_mutex_unlock(&ids->ids_lock);
328d9638e54Smws return (data);
329d9638e54Smws }
330d9638e54Smws
331d9638e54Smws void
fmd_idspace_rele(fmd_idspace_t * ids,id_t id)332d9638e54Smws fmd_idspace_rele(fmd_idspace_t *ids, id_t id)
333d9638e54Smws {
334d9638e54Smws (void) pthread_mutex_lock(&ids->ids_lock);
335d9638e54Smws
336d9638e54Smws ASSERT(fmd_idspace_lookup(ids, id) != NULL);
337d9638e54Smws ASSERT(ids->ids_refs != 0);
338d9638e54Smws ids->ids_refs--;
339d9638e54Smws
340d9638e54Smws (void) pthread_cond_broadcast(&ids->ids_cv);
341d9638e54Smws (void) pthread_mutex_unlock(&ids->ids_lock);
342d9638e54Smws }
343