1168404Spjd/*
2168404Spjd * CDDL HEADER START
3168404Spjd *
4168404Spjd * The contents of this file are subject to the terms of the
5168404Spjd * Common Development and Distribution License (the "License").
6168404Spjd * You may not use this file except in compliance with the License.
7168404Spjd *
8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9168404Spjd * or http://www.opensolaris.org/os/licensing.
10168404Spjd * See the License for the specific language governing permissions
11168404Spjd * and limitations under the License.
12168404Spjd *
13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each
14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15168404Spjd * If applicable, add the following below this CDDL HEADER, with the
16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying
17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner]
18168404Spjd *
19168404Spjd * CDDL HEADER END
20168404Spjd */
21168404Spjd/*
22185029Spjd * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23168404Spjd * Use is subject to license terms.
24168404Spjd */
25168404Spjd
26168404Spjd#pragma ident	"%Z%%M%	%I%	%E% SMI"
27168404Spjd
28168404Spjd#include <sys/zfs_context.h>
29168404Spjd#include <sys/avl.h>
30168404Spjd#include <sys/unique.h>
31168404Spjd
32168404Spjdstatic avl_tree_t unique_avl;
33185029Spjdstatic kmutex_t unique_mtx;
34168404Spjd
35168404Spjdtypedef struct unique {
36168404Spjd	avl_node_t un_link;
37168404Spjd	uint64_t un_value;
38168404Spjd} unique_t;
39168404Spjd
40168404Spjd#define	UNIQUE_MASK ((1ULL << UNIQUE_BITS) - 1)
41168404Spjd
42168404Spjdstatic int
43168404Spjdunique_compare(const void *a, const void *b)
44168404Spjd{
45168404Spjd	const unique_t *una = a;
46168404Spjd	const unique_t *unb = b;
47168404Spjd
48168404Spjd	if (una->un_value < unb->un_value)
49168404Spjd		return (-1);
50168404Spjd	if (una->un_value > unb->un_value)
51168404Spjd		return (+1);
52168404Spjd	return (0);
53168404Spjd}
54168404Spjd
55168404Spjdvoid
56168404Spjdunique_init(void)
57168404Spjd{
58168404Spjd	avl_create(&unique_avl, unique_compare,
59168404Spjd	    sizeof (unique_t), offsetof(unique_t, un_link));
60185029Spjd	mutex_init(&unique_mtx, NULL, MUTEX_DEFAULT, NULL);
61168404Spjd}
62168404Spjd
63185029Spjdvoid
64185029Spjdunique_fini(void)
65185029Spjd{
66185029Spjd	avl_destroy(&unique_avl);
67185029Spjd	mutex_destroy(&unique_mtx);
68185029Spjd}
69185029Spjd
70168404Spjduint64_t
71168404Spjdunique_create(void)
72168404Spjd{
73185029Spjd	uint64_t value = unique_insert(0);
74185029Spjd	unique_remove(value);
75185029Spjd	return (value);
76168404Spjd}
77168404Spjd
78168404Spjduint64_t
79168404Spjdunique_insert(uint64_t value)
80168404Spjd{
81168404Spjd	avl_index_t idx;
82168404Spjd	unique_t *un = kmem_alloc(sizeof (unique_t), KM_SLEEP);
83168404Spjd
84168404Spjd	un->un_value = value;
85168404Spjd
86168404Spjd	mutex_enter(&unique_mtx);
87168404Spjd	while (un->un_value == 0 || un->un_value & ~UNIQUE_MASK ||
88168404Spjd	    avl_find(&unique_avl, un, &idx)) {
89168404Spjd		mutex_exit(&unique_mtx);
90168404Spjd		(void) random_get_pseudo_bytes((void*)&un->un_value,
91168404Spjd		    sizeof (un->un_value));
92168404Spjd		un->un_value &= UNIQUE_MASK;
93168404Spjd		mutex_enter(&unique_mtx);
94168404Spjd	}
95168404Spjd
96168404Spjd	avl_insert(&unique_avl, un, idx);
97168404Spjd	mutex_exit(&unique_mtx);
98168404Spjd
99168404Spjd	return (un->un_value);
100168404Spjd}
101168404Spjd
102168404Spjdvoid
103168404Spjdunique_remove(uint64_t value)
104168404Spjd{
105168404Spjd	unique_t un_tofind;
106168404Spjd	unique_t *un;
107168404Spjd
108168404Spjd	un_tofind.un_value = value;
109168404Spjd	mutex_enter(&unique_mtx);
110168404Spjd	un = avl_find(&unique_avl, &un_tofind, NULL);
111168404Spjd	if (un != NULL) {
112168404Spjd		avl_remove(&unique_avl, un);
113168404Spjd		kmem_free(un, sizeof (unique_t));
114168404Spjd	}
115168404Spjd	mutex_exit(&unique_mtx);
116168404Spjd}
117