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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/id_space.h> 28 #include <sys/debug.h> 29 30 /* 31 * ID Spaces 32 * 33 * The id_space_t provides a simple implementation of a managed range of 34 * integer identifiers using a vmem arena. An ID space guarantees that the 35 * next identifer returned by an allocation is larger than the previous one, 36 * unless there are no larger slots remaining in the range. In this case, 37 * the ID space will return the first available slot in the lower part of the 38 * range (viewing the previous identifier as a partitioning element). If no 39 * slots are available, id_alloc()/id_allocff() will sleep until an 40 * identifier becomes available. Accordingly, id_space allocations must be 41 * initiated from contexts where sleeping is acceptable. id_alloc_nosleep()/ 42 * id_allocff_nosleep() will return -1 if no slots are available or if the 43 * system is low on memory. If id_alloc_nosleep() fails, callers should 44 * not try to extend the ID space. This is to avoid making a possible 45 * low-memory situation worse. 46 * 47 * As an ID space is designed for representing a range of id_t's, there 48 * is a preexisting maximal range: [0, MAXUID]. ID space requests outside 49 * that range will fail on a DEBUG kernel. The id_allocff*() functions 50 * return the first available id, and should be used when there is benifit 51 * to having a compact allocated range. 52 * 53 * (Presently, the id_space_t abstraction supports only direct allocations; ID 54 * reservation, in which an ID is allocated but placed in a internal 55 * dictionary for later use, should be added when a consuming subsystem 56 * arrives.) 57 */ 58 59 /* 60 * Create an arena to represent the range [low, high). 61 * Caller must be in a context in which VM_SLEEP is legal. 62 */ 63 id_space_t * 64 id_space_create(const char *name, id_t low, id_t high) 65 { 66 ASSERT(low >= 0); 67 ASSERT(low < high); 68 69 return (vmem_create(name, (void *)(uintptr_t)(low + 1), high - low, 1, 70 NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER)); 71 } 72 73 /* 74 * Destroy a previously created ID space. 75 * No restrictions on caller's context. 76 */ 77 void 78 id_space_destroy(id_space_t *isp) 79 { 80 vmem_destroy(isp); 81 } 82 83 void 84 id_space_extend(id_space_t *isp, id_t low, id_t high) 85 { 86 (void) vmem_add(isp, 87 (void *)(uintptr_t)(low + 1), high - low, VM_SLEEP); 88 } 89 90 /* 91 * Allocate an id_t from specified ID space. 92 * Caller must be in a context in which VM_SLEEP is legal. 93 */ 94 id_t 95 id_alloc(id_space_t *isp) 96 { 97 return ((id_t)(uintptr_t) 98 vmem_alloc(isp, 1, VM_SLEEP | VM_NEXTFIT) - 1); 99 } 100 101 /* 102 * Allocate an id_t from specified ID space. 103 * Returns -1 on failure (see module block comments for more information on 104 * failure modes). 105 */ 106 id_t 107 id_alloc_nosleep(id_space_t *isp) 108 { 109 return ((id_t)(uintptr_t) 110 vmem_alloc(isp, 1, VM_NOSLEEP | VM_NEXTFIT) - 1); 111 } 112 113 /* 114 * Allocate an id_t from specified ID space using FIRSTFIT. 115 * Caller must be in a context in which VM_SLEEP is legal. 116 */ 117 id_t 118 id_allocff(id_space_t *isp) 119 { 120 return ((id_t)(uintptr_t) 121 vmem_alloc(isp, 1, VM_SLEEP | VM_FIRSTFIT) - 1); 122 } 123 124 /* 125 * Allocate an id_t from specified ID space using FIRSTFIT 126 * Returns -1 on failure (see module block comments for more information on 127 * failure modes). 128 */ 129 id_t 130 id_allocff_nosleep(id_space_t *isp) 131 { 132 return ((id_t)(uintptr_t) 133 vmem_alloc(isp, 1, VM_NOSLEEP | VM_FIRSTFIT) - 1); 134 } 135 136 /* 137 * Free a previously allocated ID. 138 * No restrictions on caller's context. 139 */ 140 void 141 id_free(id_space_t *isp, id_t id) 142 { 143 vmem_free(isp, (void *)(uintptr_t)(id + 1), 1); 144 } 145