17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 54c06356bSdh142964 * Common Development and Distribution License (the "License"). 64c06356bSdh142964 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*0fbb751dSJohn Levon * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate #include <sys/types.h> 267c478bd9Sstevel@tonic-gate #include <sys/id_space.h> 277c478bd9Sstevel@tonic-gate #include <sys/debug.h> 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * ID Spaces 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * The id_space_t provides a simple implementation of a managed range of 337c478bd9Sstevel@tonic-gate * integer identifiers using a vmem arena. An ID space guarantees that the 347c478bd9Sstevel@tonic-gate * next identifer returned by an allocation is larger than the previous one, 357c478bd9Sstevel@tonic-gate * unless there are no larger slots remaining in the range. In this case, 367c478bd9Sstevel@tonic-gate * the ID space will return the first available slot in the lower part of the 377c478bd9Sstevel@tonic-gate * range (viewing the previous identifier as a partitioning element). If no 384c06356bSdh142964 * slots are available, id_alloc()/id_allocff() will sleep until an 394c06356bSdh142964 * identifier becomes available. Accordingly, id_space allocations must be 404c06356bSdh142964 * initiated from contexts where sleeping is acceptable. id_alloc_nosleep()/ 414c06356bSdh142964 * id_allocff_nosleep() will return -1 if no slots are available or if the 424c06356bSdh142964 * system is low on memory. If id_alloc_nosleep() fails, callers should 434c06356bSdh142964 * not try to extend the ID space. This is to avoid making a possible 444c06356bSdh142964 * low-memory situation worse. 457c478bd9Sstevel@tonic-gate * 467c478bd9Sstevel@tonic-gate * As an ID space is designed for representing a range of id_t's, there 474c06356bSdh142964 * is a preexisting maximal range: [0, MAXUID]. ID space requests outside 484c06356bSdh142964 * that range will fail on a DEBUG kernel. The id_allocff*() functions 49*0fbb751dSJohn Levon * return the first available id, and should be used when there is benefit 504c06356bSdh142964 * to having a compact allocated range. 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * (Presently, the id_space_t abstraction supports only direct allocations; ID 537c478bd9Sstevel@tonic-gate * reservation, in which an ID is allocated but placed in a internal 547c478bd9Sstevel@tonic-gate * dictionary for later use, should be added when a consuming subsystem 557c478bd9Sstevel@tonic-gate * arrives.) 567c478bd9Sstevel@tonic-gate */ 577c478bd9Sstevel@tonic-gate 58*0fbb751dSJohn Levon #define ID_TO_ADDR(id) ((void *)(uintptr_t)(id + 1)) 59*0fbb751dSJohn Levon #define ADDR_TO_ID(addr) ((id_t)((uintptr_t)addr - 1)) 60*0fbb751dSJohn Levon 617c478bd9Sstevel@tonic-gate /* 627c478bd9Sstevel@tonic-gate * Create an arena to represent the range [low, high). 637c478bd9Sstevel@tonic-gate * Caller must be in a context in which VM_SLEEP is legal. 647c478bd9Sstevel@tonic-gate */ 657c478bd9Sstevel@tonic-gate id_space_t * 667c478bd9Sstevel@tonic-gate id_space_create(const char *name, id_t low, id_t high) 677c478bd9Sstevel@tonic-gate { 687c478bd9Sstevel@tonic-gate ASSERT(low >= 0); 697c478bd9Sstevel@tonic-gate ASSERT(low < high); 707c478bd9Sstevel@tonic-gate 71*0fbb751dSJohn Levon return (vmem_create(name, ID_TO_ADDR(low), high - low, 1, 727c478bd9Sstevel@tonic-gate NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER)); 737c478bd9Sstevel@tonic-gate } 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate /* 767c478bd9Sstevel@tonic-gate * Destroy a previously created ID space. 777c478bd9Sstevel@tonic-gate * No restrictions on caller's context. 787c478bd9Sstevel@tonic-gate */ 797c478bd9Sstevel@tonic-gate void 807c478bd9Sstevel@tonic-gate id_space_destroy(id_space_t *isp) 817c478bd9Sstevel@tonic-gate { 827c478bd9Sstevel@tonic-gate vmem_destroy(isp); 837c478bd9Sstevel@tonic-gate } 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate void 867c478bd9Sstevel@tonic-gate id_space_extend(id_space_t *isp, id_t low, id_t high) 877c478bd9Sstevel@tonic-gate { 88*0fbb751dSJohn Levon (void) vmem_add(isp, ID_TO_ADDR(low), high - low, VM_SLEEP); 897c478bd9Sstevel@tonic-gate } 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate /* 927c478bd9Sstevel@tonic-gate * Allocate an id_t from specified ID space. 937c478bd9Sstevel@tonic-gate * Caller must be in a context in which VM_SLEEP is legal. 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate id_t 967c478bd9Sstevel@tonic-gate id_alloc(id_space_t *isp) 977c478bd9Sstevel@tonic-gate { 98*0fbb751dSJohn Levon return (ADDR_TO_ID(vmem_alloc(isp, 1, VM_SLEEP | VM_NEXTFIT))); 997c478bd9Sstevel@tonic-gate } 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * Allocate an id_t from specified ID space. 1037c478bd9Sstevel@tonic-gate * Returns -1 on failure (see module block comments for more information on 1047c478bd9Sstevel@tonic-gate * failure modes). 1057c478bd9Sstevel@tonic-gate */ 1067c478bd9Sstevel@tonic-gate id_t 1077c478bd9Sstevel@tonic-gate id_alloc_nosleep(id_space_t *isp) 1087c478bd9Sstevel@tonic-gate { 109*0fbb751dSJohn Levon return (ADDR_TO_ID(vmem_alloc(isp, 1, VM_NOSLEEP | VM_NEXTFIT))); 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate /* 1134c06356bSdh142964 * Allocate an id_t from specified ID space using FIRSTFIT. 1144c06356bSdh142964 * Caller must be in a context in which VM_SLEEP is legal. 1154c06356bSdh142964 */ 1164c06356bSdh142964 id_t 1174c06356bSdh142964 id_allocff(id_space_t *isp) 1184c06356bSdh142964 { 119*0fbb751dSJohn Levon return (ADDR_TO_ID(vmem_alloc(isp, 1, VM_SLEEP | VM_FIRSTFIT))); 1204c06356bSdh142964 } 1214c06356bSdh142964 1224c06356bSdh142964 /* 1234c06356bSdh142964 * Allocate an id_t from specified ID space using FIRSTFIT 1244c06356bSdh142964 * Returns -1 on failure (see module block comments for more information on 1254c06356bSdh142964 * failure modes). 1264c06356bSdh142964 */ 1274c06356bSdh142964 id_t 1284c06356bSdh142964 id_allocff_nosleep(id_space_t *isp) 1294c06356bSdh142964 { 130*0fbb751dSJohn Levon return (ADDR_TO_ID(vmem_alloc(isp, 1, VM_NOSLEEP | VM_FIRSTFIT))); 131*0fbb751dSJohn Levon } 132*0fbb751dSJohn Levon 133*0fbb751dSJohn Levon /* 134*0fbb751dSJohn Levon * Allocate a specific identifier if possible, returning the id if 135*0fbb751dSJohn Levon * successful, or -1 on failure. 136*0fbb751dSJohn Levon */ 137*0fbb751dSJohn Levon id_t 138*0fbb751dSJohn Levon id_alloc_specific_nosleep(id_space_t *isp, id_t id) 139*0fbb751dSJohn Levon { 140*0fbb751dSJohn Levon void *minaddr = ID_TO_ADDR(id); 141*0fbb751dSJohn Levon void *maxaddr = ID_TO_ADDR(id + 1); 142*0fbb751dSJohn Levon 143*0fbb751dSJohn Levon /* 144*0fbb751dSJohn Levon * Note that even though we're vmem_free()ing this later, it 145*0fbb751dSJohn Levon * should be OK, since there's no quantum cache. 146*0fbb751dSJohn Levon */ 147*0fbb751dSJohn Levon return (ADDR_TO_ID(vmem_xalloc(isp, 1, 1, 0, 0, 148*0fbb751dSJohn Levon minaddr, maxaddr, VM_NOSLEEP))); 1494c06356bSdh142964 } 1504c06356bSdh142964 1514c06356bSdh142964 /* 1527c478bd9Sstevel@tonic-gate * Free a previously allocated ID. 1537c478bd9Sstevel@tonic-gate * No restrictions on caller's context. 1547c478bd9Sstevel@tonic-gate */ 1557c478bd9Sstevel@tonic-gate void 1567c478bd9Sstevel@tonic-gate id_free(id_space_t *isp, id_t id) 1577c478bd9Sstevel@tonic-gate { 158*0fbb751dSJohn Levon vmem_free(isp, ID_TO_ADDR(id), 1); 1597c478bd9Sstevel@tonic-gate } 160