1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 #include <sys/zfs_context.h>
  29 #include <sys/avl.h>
  30 #include <sys/unique.h>
  31 
  32 static avl_tree_t unique_avl;
  33 static kmutex_t unique_mtx;
  34 
  35 typedef struct unique {
  36         avl_node_t un_link;
  37         uint64_t un_value;
  38 } unique_t;
  39 
  40 #define UNIQUE_MASK ((1ULL << UNIQUE_BITS) - 1)
  41 
  42 static int
  43 unique_compare(const void *a, const void *b)
  44 {
  45         const unique_t *una = a;
  46         const unique_t *unb = b;
  47 
  48         if (una->un_value < unb->un_value)
  49                 return (-1);
  50         if (una->un_value > unb->un_value)
  51                 return (+1);
  52         return (0);
  53 }
  54 
  55 void
  56 unique_init(void)
  57 {
  58         avl_create(&unique_avl, unique_compare,
  59             sizeof (unique_t), offsetof(unique_t, un_link));
  60         mutex_init(&unique_mtx, NULL, MUTEX_DEFAULT, NULL);
  61 }
  62 
  63 void
  64 unique_fini(void)
  65 {
  66         avl_destroy(&unique_avl);
  67         mutex_destroy(&unique_mtx);
  68 }
  69 
  70 uint64_t
  71 unique_create(void)
  72 {
  73         uint64_t value = unique_insert(0);
  74         unique_remove(value);
  75         return (value);
  76 }
  77 
  78 uint64_t
  79 unique_insert(uint64_t value)
  80 {
  81         avl_index_t idx;
  82         unique_t *un = kmem_alloc(sizeof (unique_t), KM_SLEEP);
  83 
  84         un->un_value = value;
  85 
  86         mutex_enter(&unique_mtx);
  87         while (un->un_value == 0 || un->un_value & ~UNIQUE_MASK ||
  88             avl_find(&unique_avl, un, &idx)) {
  89                 mutex_exit(&unique_mtx);
  90                 (void) random_get_pseudo_bytes((void*)&un->un_value,
  91                     sizeof (un->un_value));
  92                 un->un_value &= UNIQUE_MASK;
  93                 mutex_enter(&unique_mtx);
  94         }
  95 
  96         avl_insert(&unique_avl, un, idx);
  97         mutex_exit(&unique_mtx);
  98 
  99         return (un->un_value);
 100 }
 101 
 102 void
 103 unique_remove(uint64_t value)
 104 {
 105         unique_t un_tofind;
 106         unique_t *un;
 107 
 108         un_tofind.un_value = value;
 109         mutex_enter(&unique_mtx);
 110         un = avl_find(&unique_avl, &un_tofind, NULL);
 111         if (un != NULL) {
 112                 avl_remove(&unique_avl, un);
 113                 kmem_free(un, sizeof (unique_t));
 114         }
 115         mutex_exit(&unique_mtx);
 116 }