xref: /illumos-gate/usr/src/common/idspace/id_space.c (revision 01aad269)
1*01aad269SRobert Mustacchi /*
2*01aad269SRobert Mustacchi  * CDDL HEADER START
3*01aad269SRobert Mustacchi  *
4*01aad269SRobert Mustacchi  * The contents of this file are subject to the terms of the
5*01aad269SRobert Mustacchi  * Common Development and Distribution License (the "License").
6*01aad269SRobert Mustacchi  * You may not use this file except in compliance with the License.
7*01aad269SRobert Mustacchi  *
8*01aad269SRobert Mustacchi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*01aad269SRobert Mustacchi  * or http://www.opensolaris.org/os/licensing.
10*01aad269SRobert Mustacchi  * See the License for the specific language governing permissions
11*01aad269SRobert Mustacchi  * and limitations under the License.
12*01aad269SRobert Mustacchi  *
13*01aad269SRobert Mustacchi  * When distributing Covered Code, include this CDDL HEADER in each
14*01aad269SRobert Mustacchi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*01aad269SRobert Mustacchi  * If applicable, add the following below this CDDL HEADER, with the
16*01aad269SRobert Mustacchi  * fields enclosed by brackets "[]" replaced with your own identifying
17*01aad269SRobert Mustacchi  * information: Portions Copyright [yyyy] [name of copyright owner]
18*01aad269SRobert Mustacchi  *
19*01aad269SRobert Mustacchi  * CDDL HEADER END
20*01aad269SRobert Mustacchi  */
21*01aad269SRobert Mustacchi /*
22*01aad269SRobert Mustacchi  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
23*01aad269SRobert Mustacchi  */
24*01aad269SRobert Mustacchi 
25*01aad269SRobert Mustacchi #include <sys/types.h>
26*01aad269SRobert Mustacchi #include <sys/id_space.h>
27*01aad269SRobert Mustacchi #include <sys/debug.h>
28*01aad269SRobert Mustacchi 
29*01aad269SRobert Mustacchi /*
30*01aad269SRobert Mustacchi  * ID Spaces
31*01aad269SRobert Mustacchi  *
32*01aad269SRobert Mustacchi  *   The id_space_t provides a simple implementation of a managed range of
33*01aad269SRobert Mustacchi  *   integer identifiers using a vmem arena.  An ID space guarantees that the
34*01aad269SRobert Mustacchi  *   next identifer returned by an allocation is larger than the previous one,
35*01aad269SRobert Mustacchi  *   unless there are no larger slots remaining in the range.  In this case,
36*01aad269SRobert Mustacchi  *   the ID space will return the first available slot in the lower part of the
37*01aad269SRobert Mustacchi  *   range (viewing the previous identifier as a partitioning element).  If no
38*01aad269SRobert Mustacchi  *   slots are available, id_alloc()/id_allocff() will sleep until an
39*01aad269SRobert Mustacchi  *   identifier becomes available.  Accordingly, id_space allocations must be
40*01aad269SRobert Mustacchi  *   initiated from contexts where sleeping is acceptable.  id_alloc_nosleep()/
41*01aad269SRobert Mustacchi  *   id_allocff_nosleep() will return -1 if no slots are available or if the
42*01aad269SRobert Mustacchi  *   system is low on memory.  If id_alloc_nosleep() fails, callers should
43*01aad269SRobert Mustacchi  *   not try to extend the ID space.  This is to avoid making a possible
44*01aad269SRobert Mustacchi  *   low-memory situation worse.
45*01aad269SRobert Mustacchi  *
46*01aad269SRobert Mustacchi  *   As an ID space is designed for representing a range of id_t's, there
47*01aad269SRobert Mustacchi  *   is a preexisting maximal range: [0, MAXUID].  ID space requests outside
48*01aad269SRobert Mustacchi  *   that range will fail on a DEBUG kernel.  The id_allocff*() functions
49*01aad269SRobert Mustacchi  *   return the first available id, and should be used when there is benefit
50*01aad269SRobert Mustacchi  *   to having a compact allocated range.
51*01aad269SRobert Mustacchi  *
52*01aad269SRobert Mustacchi  *   (Presently, the id_space_t abstraction supports only direct allocations; ID
53*01aad269SRobert Mustacchi  *   reservation, in which an ID is allocated but placed in a internal
54*01aad269SRobert Mustacchi  *   dictionary for later use, should be added when a consuming subsystem
55*01aad269SRobert Mustacchi  *   arrives.)
56*01aad269SRobert Mustacchi  *
57*01aad269SRobert Mustacchi  *   This code is also shared with userland. In userland, we don't have the same
58*01aad269SRobert Mustacchi  *   ability to have sleeping variants, so we effectively turn the normal
59*01aad269SRobert Mustacchi  *   versions without _nosleep into _nosleep.
60*01aad269SRobert Mustacchi  */
61*01aad269SRobert Mustacchi 
62*01aad269SRobert Mustacchi #define	ID_TO_ADDR(id) ((void *)(uintptr_t)(id + 1))
63*01aad269SRobert Mustacchi #define	ADDR_TO_ID(addr) ((id_t)((uintptr_t)addr - 1))
64*01aad269SRobert Mustacchi 
65*01aad269SRobert Mustacchi /*
66*01aad269SRobert Mustacchi  * Create an arena to represent the range [low, high).
67*01aad269SRobert Mustacchi  * Caller must be in a context in which VM_SLEEP is legal,
68*01aad269SRobert Mustacchi  * for the kernel. Always VM_NOSLEEP in userland.
69*01aad269SRobert Mustacchi  */
70*01aad269SRobert Mustacchi id_space_t *
id_space_create(const char * name,id_t low,id_t high)71*01aad269SRobert Mustacchi id_space_create(const char *name, id_t low, id_t high)
72*01aad269SRobert Mustacchi {
73*01aad269SRobert Mustacchi #ifdef _KERNEL
74*01aad269SRobert Mustacchi 	int flag = VM_SLEEP;
75*01aad269SRobert Mustacchi #else
76*01aad269SRobert Mustacchi 	int flag = VM_NOSLEEP;
77*01aad269SRobert Mustacchi #endif
78*01aad269SRobert Mustacchi 	ASSERT(low >= 0);
79*01aad269SRobert Mustacchi 	ASSERT(low < high);
80*01aad269SRobert Mustacchi 
81*01aad269SRobert Mustacchi 	return (vmem_create(name, ID_TO_ADDR(low), high - low, 1,
82*01aad269SRobert Mustacchi 	    NULL, NULL, NULL, 0, flag | VMC_IDENTIFIER));
83*01aad269SRobert Mustacchi }
84*01aad269SRobert Mustacchi 
85*01aad269SRobert Mustacchi /*
86*01aad269SRobert Mustacchi  * Destroy a previously created ID space.
87*01aad269SRobert Mustacchi  * No restrictions on caller's context.
88*01aad269SRobert Mustacchi  */
89*01aad269SRobert Mustacchi void
id_space_destroy(id_space_t * isp)90*01aad269SRobert Mustacchi id_space_destroy(id_space_t *isp)
91*01aad269SRobert Mustacchi {
92*01aad269SRobert Mustacchi 	vmem_destroy(isp);
93*01aad269SRobert Mustacchi }
94*01aad269SRobert Mustacchi 
95*01aad269SRobert Mustacchi void
id_space_extend(id_space_t * isp,id_t low,id_t high)96*01aad269SRobert Mustacchi id_space_extend(id_space_t *isp, id_t low, id_t high)
97*01aad269SRobert Mustacchi {
98*01aad269SRobert Mustacchi #ifdef _KERNEL
99*01aad269SRobert Mustacchi 	int flag = VM_SLEEP;
100*01aad269SRobert Mustacchi #else
101*01aad269SRobert Mustacchi 	int flag = VM_NOSLEEP;
102*01aad269SRobert Mustacchi #endif
103*01aad269SRobert Mustacchi 	(void) vmem_add(isp, ID_TO_ADDR(low), high - low, flag);
104*01aad269SRobert Mustacchi }
105*01aad269SRobert Mustacchi 
106*01aad269SRobert Mustacchi /*
107*01aad269SRobert Mustacchi  * Allocate an id_t from specified ID space.
108*01aad269SRobert Mustacchi  * Caller must be in a context in which VM_SLEEP is legal.
109*01aad269SRobert Mustacchi  */
110*01aad269SRobert Mustacchi id_t
id_alloc(id_space_t * isp)111*01aad269SRobert Mustacchi id_alloc(id_space_t *isp)
112*01aad269SRobert Mustacchi {
113*01aad269SRobert Mustacchi #ifdef _KERNEL
114*01aad269SRobert Mustacchi 	int flag = VM_SLEEP;
115*01aad269SRobert Mustacchi #else
116*01aad269SRobert Mustacchi 	int flag = VM_NOSLEEP;
117*01aad269SRobert Mustacchi #endif
118*01aad269SRobert Mustacchi 	return (ADDR_TO_ID(vmem_alloc(isp, 1, flag | VM_NEXTFIT)));
119*01aad269SRobert Mustacchi }
120*01aad269SRobert Mustacchi 
121*01aad269SRobert Mustacchi /*
122*01aad269SRobert Mustacchi  * Allocate an id_t from specified ID space.
123*01aad269SRobert Mustacchi  * Returns -1 on failure (see module block comments for more information on
124*01aad269SRobert Mustacchi  * failure modes).
125*01aad269SRobert Mustacchi  */
126*01aad269SRobert Mustacchi id_t
id_alloc_nosleep(id_space_t * isp)127*01aad269SRobert Mustacchi id_alloc_nosleep(id_space_t *isp)
128*01aad269SRobert Mustacchi {
129*01aad269SRobert Mustacchi 	return (ADDR_TO_ID(vmem_alloc(isp, 1, VM_NOSLEEP | VM_NEXTFIT)));
130*01aad269SRobert Mustacchi }
131*01aad269SRobert Mustacchi 
132*01aad269SRobert Mustacchi /*
133*01aad269SRobert Mustacchi  * Allocate an id_t from specified ID space using FIRSTFIT.
134*01aad269SRobert Mustacchi  * Caller must be in a context in which VM_SLEEP is legal.
135*01aad269SRobert Mustacchi  */
136*01aad269SRobert Mustacchi id_t
id_allocff(id_space_t * isp)137*01aad269SRobert Mustacchi id_allocff(id_space_t *isp)
138*01aad269SRobert Mustacchi {
139*01aad269SRobert Mustacchi #ifdef _KERNEL
140*01aad269SRobert Mustacchi 	int flag = VM_SLEEP;
141*01aad269SRobert Mustacchi #else
142*01aad269SRobert Mustacchi 	int flag = VM_NOSLEEP;
143*01aad269SRobert Mustacchi #endif
144*01aad269SRobert Mustacchi 	return (ADDR_TO_ID(vmem_alloc(isp, 1, flag | VM_FIRSTFIT)));
145*01aad269SRobert Mustacchi }
146*01aad269SRobert Mustacchi 
147*01aad269SRobert Mustacchi /*
148*01aad269SRobert Mustacchi  * Allocate an id_t from specified ID space using FIRSTFIT
149*01aad269SRobert Mustacchi  * Returns -1 on failure (see module block comments for more information on
150*01aad269SRobert Mustacchi  * failure modes).
151*01aad269SRobert Mustacchi  */
152*01aad269SRobert Mustacchi id_t
id_allocff_nosleep(id_space_t * isp)153*01aad269SRobert Mustacchi id_allocff_nosleep(id_space_t *isp)
154*01aad269SRobert Mustacchi {
155*01aad269SRobert Mustacchi 	return (ADDR_TO_ID(vmem_alloc(isp, 1, VM_NOSLEEP | VM_FIRSTFIT)));
156*01aad269SRobert Mustacchi }
157*01aad269SRobert Mustacchi 
158*01aad269SRobert Mustacchi /*
159*01aad269SRobert Mustacchi  * Allocate a specific identifier if possible, returning the id if
160*01aad269SRobert Mustacchi  * successful, or -1 on failure.
161*01aad269SRobert Mustacchi  */
162*01aad269SRobert Mustacchi id_t
id_alloc_specific_nosleep(id_space_t * isp,id_t id)163*01aad269SRobert Mustacchi id_alloc_specific_nosleep(id_space_t *isp, id_t id)
164*01aad269SRobert Mustacchi {
165*01aad269SRobert Mustacchi 	void *minaddr = ID_TO_ADDR(id);
166*01aad269SRobert Mustacchi 	void *maxaddr = ID_TO_ADDR(id + 1);
167*01aad269SRobert Mustacchi 
168*01aad269SRobert Mustacchi 	/*
169*01aad269SRobert Mustacchi 	 * Note that even though we're vmem_free()ing this later, it
170*01aad269SRobert Mustacchi 	 * should be OK, since there's no quantum cache.
171*01aad269SRobert Mustacchi 	 */
172*01aad269SRobert Mustacchi 	return (ADDR_TO_ID(vmem_xalloc(isp, 1, 1, 0, 0,
173*01aad269SRobert Mustacchi 	    minaddr, maxaddr, VM_NOSLEEP)));
174*01aad269SRobert Mustacchi }
175*01aad269SRobert Mustacchi 
176*01aad269SRobert Mustacchi /*
177*01aad269SRobert Mustacchi  * Free a previously allocated ID.
178*01aad269SRobert Mustacchi  * No restrictions on caller's context.
179*01aad269SRobert Mustacchi  */
180*01aad269SRobert Mustacchi void
id_free(id_space_t * isp,id_t id)181*01aad269SRobert Mustacchi id_free(id_space_t *isp, id_t id)
182*01aad269SRobert Mustacchi {
183*01aad269SRobert Mustacchi 	vmem_free(isp, ID_TO_ADDR(id), 1);
184*01aad269SRobert Mustacchi }
185