xref: /titanic_41/usr/src/uts/common/os/id_space.c (revision 986fd29a0dc13f7608ef7f508f6e700bd7bc2720)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/id_space.h>
31 #include <sys/debug.h>
32 
33 /*
34  * ID Spaces
35  *
36  *   The id_space_t provides a simple implementation of a managed range of
37  *   integer identifiers using a vmem arena.  An ID space guarantees that the
38  *   next identifer returned by an allocation is larger than the previous one,
39  *   unless there are no larger slots remaining in the range.  In this case,
40  *   the ID space will return the first available slot in the lower part of the
41  *   range (viewing the previous identifier as a partitioning element).  If no
42  *   slots are available, id_alloc() will sleep until an identifier becomes
43  *   available.  Accordingly, id_space allocations must be initiated from
44  *   contexts where sleeping is acceptable.  id_alloc_nosleep() will return
45  *   -1 if no slots are available or if the system is low on memory.  If
46  *   id_alloc_nosleep() fails, callers should not try to extend the ID
47  *   space.  This is to avoid making a possible low-memory situation
48  *   worse.
49  *
50  *   As an ID space is designed for representing a range of id_t's, there
51  *   is a preexisting maximal range: [0, MAXUID].  ID space requests
52  *   outside that range will fail on a DEBUG kernel.
53  *
54  *   (Presently, the id_space_t abstraction supports only direct allocations; ID
55  *   reservation, in which an ID is allocated but placed in a internal
56  *   dictionary for later use, should be added when a consuming subsystem
57  *   arrives.)
58  */
59 
60 /*
61  * Create an arena to represent the range [low, high).
62  * Caller must be in a context in which VM_SLEEP is legal.
63  */
64 id_space_t *
65 id_space_create(const char *name, id_t low, id_t high)
66 {
67 	ASSERT(low >= 0);
68 	ASSERT(low < high);
69 
70 	return (vmem_create(name, (void *)(uintptr_t)(low + 1), high - low, 1,
71 	    NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER));
72 }
73 
74 /*
75  * Destroy a previously created ID space.
76  * No restrictions on caller's context.
77  */
78 void
79 id_space_destroy(id_space_t *isp)
80 {
81 	vmem_destroy(isp);
82 }
83 
84 void
85 id_space_extend(id_space_t *isp, id_t low, id_t high)
86 {
87 	(void) vmem_add(isp,
88 	    (void *)(uintptr_t)(low + 1), high - low, VM_SLEEP);
89 }
90 
91 /*
92  * Allocate an id_t from specified ID space.
93  * Caller must be in a context in which VM_SLEEP is legal.
94  */
95 id_t
96 id_alloc(id_space_t *isp)
97 {
98 	return ((id_t)(uintptr_t)
99 	    vmem_alloc(isp, 1, VM_SLEEP | VM_NEXTFIT) - 1);
100 }
101 
102 /*
103  * Allocate an id_t from specified ID space.
104  * Returns -1 on failure (see module block comments for more information on
105  * failure modes).
106  */
107 id_t
108 id_alloc_nosleep(id_space_t *isp)
109 {
110 	return ((id_t)(uintptr_t)
111 	    vmem_alloc(isp, 1, VM_NOSLEEP | VM_NEXTFIT) - 1);
112 }
113 
114 /*
115  * Free a previously allocated ID.
116  * No restrictions on caller's context.
117  */
118 void
119 id_free(id_space_t *isp, id_t id)
120 {
121 	vmem_free(isp, (void *)(uintptr_t)(id + 1), 1);
122 }
123