11ba4a712SPawel Jakub Dawidek /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 38a36da99SPedro F. Giffuni * 41ba4a712SPawel Jakub Dawidek * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 51ba4a712SPawel Jakub Dawidek * All rights reserved. 61ba4a712SPawel Jakub Dawidek * 71ba4a712SPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 81ba4a712SPawel Jakub Dawidek * modification, are permitted provided that the following conditions 91ba4a712SPawel Jakub Dawidek * are met: 101ba4a712SPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 111ba4a712SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 121ba4a712SPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 131ba4a712SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 141ba4a712SPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 151ba4a712SPawel Jakub Dawidek * 161ba4a712SPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 171ba4a712SPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 181ba4a712SPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 191ba4a712SPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 201ba4a712SPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 211ba4a712SPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 221ba4a712SPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 231ba4a712SPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 241ba4a712SPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251ba4a712SPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261ba4a712SPawel Jakub Dawidek * SUCH DAMAGE. 271ba4a712SPawel Jakub Dawidek */ 281ba4a712SPawel Jakub Dawidek 291ba4a712SPawel Jakub Dawidek #include <sys/cdefs.h> 301ba4a712SPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 311ba4a712SPawel Jakub Dawidek 321ba4a712SPawel Jakub Dawidek #include <sys/param.h> 331ba4a712SPawel Jakub Dawidek #include <sys/kernel.h> 341ba4a712SPawel Jakub Dawidek #include <sys/systm.h> 351ba4a712SPawel Jakub Dawidek #include <sys/sysctl.h> 361ba4a712SPawel Jakub Dawidek #include <sys/errno.h> 3749939083SJamie Gritton #include <sys/jail.h> 381ba4a712SPawel Jakub Dawidek #include <sys/malloc.h> 391ba4a712SPawel Jakub Dawidek #include <sys/lock.h> 401ba4a712SPawel Jakub Dawidek #include <sys/mutex.h> 4161304249SJamie Gritton #include <sys/rmlock.h> 4261304249SJamie Gritton #include <sys/sx.h> 431ba4a712SPawel Jakub Dawidek #include <sys/queue.h> 441ba4a712SPawel Jakub Dawidek #include <sys/proc.h> 451ba4a712SPawel Jakub Dawidek #include <sys/osd.h> 461ba4a712SPawel Jakub Dawidek 471ba4a712SPawel Jakub Dawidek /* OSD (Object Specific Data) */ 481ba4a712SPawel Jakub Dawidek 49859f4d06SJamie Gritton /* 50859f4d06SJamie Gritton * Lock key: 51859f4d06SJamie Gritton * (m) osd_module_lock 52859f4d06SJamie Gritton * (o) osd_object_lock 53859f4d06SJamie Gritton * (l) osd_list_lock 54859f4d06SJamie Gritton */ 55859f4d06SJamie Gritton struct osd_master { 56859f4d06SJamie Gritton struct sx osd_module_lock; 57859f4d06SJamie Gritton struct rmlock osd_object_lock; 58859f4d06SJamie Gritton struct mtx osd_list_lock; 59320d8421SJamie Gritton LIST_HEAD(, osd) osd_list; /* (l) */ 60859f4d06SJamie Gritton osd_destructor_t *osd_destructors; /* (o) */ 61859f4d06SJamie Gritton osd_method_t *osd_methods; /* (m) */ 62859f4d06SJamie Gritton u_int osd_ntslots; /* (m) */ 63859f4d06SJamie Gritton const u_int osd_nmethods; 64859f4d06SJamie Gritton }; 65859f4d06SJamie Gritton 661ba4a712SPawel Jakub Dawidek static MALLOC_DEFINE(M_OSD, "osd", "Object Specific Data"); 671ba4a712SPawel Jakub Dawidek 681ba4a712SPawel Jakub Dawidek static int osd_debug = 0; 69af3b2549SHans Petter Selasky SYSCTL_INT(_debug, OID_AUTO, osd, CTLFLAG_RWTUN, &osd_debug, 0, "OSD debug level"); 701ba4a712SPawel Jakub Dawidek 711ba4a712SPawel Jakub Dawidek #define OSD_DEBUG(...) do { \ 721ba4a712SPawel Jakub Dawidek if (osd_debug) { \ 731ba4a712SPawel Jakub Dawidek printf("OSD (%s:%u): ", __func__, __LINE__); \ 741ba4a712SPawel Jakub Dawidek printf(__VA_ARGS__); \ 751ba4a712SPawel Jakub Dawidek printf("\n"); \ 761ba4a712SPawel Jakub Dawidek } \ 771ba4a712SPawel Jakub Dawidek } while (0) 781ba4a712SPawel Jakub Dawidek 7961304249SJamie Gritton static void do_osd_del(u_int type, struct osd *osd, u_int slot, 8061304249SJamie Gritton int list_locked); 8161304249SJamie Gritton 821ba4a712SPawel Jakub Dawidek /* 83859f4d06SJamie Gritton * List of objects with OSD. 841ba4a712SPawel Jakub Dawidek */ 85859f4d06SJamie Gritton struct osd_master osdm[OSD_LAST + 1] = { 86859f4d06SJamie Gritton [OSD_JAIL] = { .osd_nmethods = PR_MAXMETHOD }, 87b38ff370SJamie Gritton }; 8861304249SJamie Gritton 891ba4a712SPawel Jakub Dawidek static void 901ba4a712SPawel Jakub Dawidek osd_default_destructor(void *value __unused) 911ba4a712SPawel Jakub Dawidek { 921ba4a712SPawel Jakub Dawidek /* Do nothing. */ 931ba4a712SPawel Jakub Dawidek } 941ba4a712SPawel Jakub Dawidek 951ba4a712SPawel Jakub Dawidek int 9661304249SJamie Gritton osd_register(u_int type, osd_destructor_t destructor, osd_method_t *methods) 971ba4a712SPawel Jakub Dawidek { 981ba4a712SPawel Jakub Dawidek void *newptr; 9961304249SJamie Gritton u_int i, m; 1001ba4a712SPawel Jakub Dawidek 1011ba4a712SPawel Jakub Dawidek KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); 1021ba4a712SPawel Jakub Dawidek 1031ba4a712SPawel Jakub Dawidek /* 1041ba4a712SPawel Jakub Dawidek * If no destructor is given, use default one. We need to use some 1051ba4a712SPawel Jakub Dawidek * destructor, because NULL destructor means unused slot. 1061ba4a712SPawel Jakub Dawidek */ 1071ba4a712SPawel Jakub Dawidek if (destructor == NULL) 1081ba4a712SPawel Jakub Dawidek destructor = osd_default_destructor; 1091ba4a712SPawel Jakub Dawidek 110859f4d06SJamie Gritton sx_xlock(&osdm[type].osd_module_lock); 1111ba4a712SPawel Jakub Dawidek /* 1121ba4a712SPawel Jakub Dawidek * First, we try to find unused slot. 1131ba4a712SPawel Jakub Dawidek */ 114859f4d06SJamie Gritton for (i = 0; i < osdm[type].osd_ntslots; i++) { 115859f4d06SJamie Gritton if (osdm[type].osd_destructors[i] == NULL) { 1161ba4a712SPawel Jakub Dawidek OSD_DEBUG("Unused slot found (type=%u, slot=%u).", 1171ba4a712SPawel Jakub Dawidek type, i); 1181ba4a712SPawel Jakub Dawidek break; 1191ba4a712SPawel Jakub Dawidek } 1201ba4a712SPawel Jakub Dawidek } 1211ba4a712SPawel Jakub Dawidek /* 1221ba4a712SPawel Jakub Dawidek * If no unused slot was found, allocate one. 1231ba4a712SPawel Jakub Dawidek */ 124859f4d06SJamie Gritton if (i == osdm[type].osd_ntslots) { 125859f4d06SJamie Gritton osdm[type].osd_ntslots++; 126859f4d06SJamie Gritton if (osdm[type].osd_nmethods != 0) 127859f4d06SJamie Gritton osdm[type].osd_methods = realloc(osdm[type].osd_methods, 128859f4d06SJamie Gritton sizeof(osd_method_t) * osdm[type].osd_ntslots * 129859f4d06SJamie Gritton osdm[type].osd_nmethods, M_OSD, M_WAITOK); 130859f4d06SJamie Gritton newptr = malloc(sizeof(osd_destructor_t) * 131859f4d06SJamie Gritton osdm[type].osd_ntslots, M_OSD, M_WAITOK); 132859f4d06SJamie Gritton rm_wlock(&osdm[type].osd_object_lock); 133859f4d06SJamie Gritton bcopy(osdm[type].osd_destructors, newptr, 13461304249SJamie Gritton sizeof(osd_destructor_t) * i); 135859f4d06SJamie Gritton free(osdm[type].osd_destructors, M_OSD); 136859f4d06SJamie Gritton osdm[type].osd_destructors = newptr; 137859f4d06SJamie Gritton rm_wunlock(&osdm[type].osd_object_lock); 1381ba4a712SPawel Jakub Dawidek OSD_DEBUG("New slot allocated (type=%u, slot=%u).", 1391ba4a712SPawel Jakub Dawidek type, i + 1); 1401ba4a712SPawel Jakub Dawidek } 14161304249SJamie Gritton 142859f4d06SJamie Gritton osdm[type].osd_destructors[i] = destructor; 143859f4d06SJamie Gritton if (osdm[type].osd_nmethods != 0) { 144859f4d06SJamie Gritton for (m = 0; m < osdm[type].osd_nmethods; m++) 145859f4d06SJamie Gritton osdm[type].osd_methods[i * osdm[type].osd_nmethods + m] 146859f4d06SJamie Gritton = methods != NULL ? methods[m] : NULL; 14761304249SJamie Gritton } 148859f4d06SJamie Gritton sx_xunlock(&osdm[type].osd_module_lock); 1491ba4a712SPawel Jakub Dawidek return (i + 1); 1501ba4a712SPawel Jakub Dawidek } 1511ba4a712SPawel Jakub Dawidek 1521ba4a712SPawel Jakub Dawidek void 1531ba4a712SPawel Jakub Dawidek osd_deregister(u_int type, u_int slot) 1541ba4a712SPawel Jakub Dawidek { 1551ba4a712SPawel Jakub Dawidek struct osd *osd, *tosd; 1561ba4a712SPawel Jakub Dawidek 1571ba4a712SPawel Jakub Dawidek KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); 1581ba4a712SPawel Jakub Dawidek KASSERT(slot > 0, ("Invalid slot.")); 1591ba4a712SPawel Jakub Dawidek 160859f4d06SJamie Gritton sx_xlock(&osdm[type].osd_module_lock); 161859f4d06SJamie Gritton rm_wlock(&osdm[type].osd_object_lock); 162187afc58SMark Johnston KASSERT(osdm[type].osd_destructors[slot - 1] != NULL, ("Unused slot.")); 163187afc58SMark Johnston 1641ba4a712SPawel Jakub Dawidek /* 1651ba4a712SPawel Jakub Dawidek * Free all OSD for the given slot. 1661ba4a712SPawel Jakub Dawidek */ 167859f4d06SJamie Gritton mtx_lock(&osdm[type].osd_list_lock); 168859f4d06SJamie Gritton LIST_FOREACH_SAFE(osd, &osdm[type].osd_list, osd_next, tosd) 16961304249SJamie Gritton do_osd_del(type, osd, slot, 1); 170859f4d06SJamie Gritton mtx_unlock(&osdm[type].osd_list_lock); 1711ba4a712SPawel Jakub Dawidek /* 1721ba4a712SPawel Jakub Dawidek * Set destructor to NULL to free the slot. 1731ba4a712SPawel Jakub Dawidek */ 174859f4d06SJamie Gritton osdm[type].osd_destructors[slot - 1] = NULL; 175859f4d06SJamie Gritton if (slot == osdm[type].osd_ntslots) { 176859f4d06SJamie Gritton osdm[type].osd_ntslots--; 177859f4d06SJamie Gritton osdm[type].osd_destructors = realloc(osdm[type].osd_destructors, 178859f4d06SJamie Gritton sizeof(osd_destructor_t) * osdm[type].osd_ntslots, M_OSD, 1791ba4a712SPawel Jakub Dawidek M_NOWAIT | M_ZERO); 180859f4d06SJamie Gritton if (osdm[type].osd_nmethods != 0) 181859f4d06SJamie Gritton osdm[type].osd_methods = realloc(osdm[type].osd_methods, 182859f4d06SJamie Gritton sizeof(osd_method_t) * osdm[type].osd_ntslots * 183859f4d06SJamie Gritton osdm[type].osd_nmethods, M_OSD, M_NOWAIT | M_ZERO); 1841ba4a712SPawel Jakub Dawidek /* 1851ba4a712SPawel Jakub Dawidek * We always reallocate to smaller size, so we assume it will 1861ba4a712SPawel Jakub Dawidek * always succeed. 1871ba4a712SPawel Jakub Dawidek */ 188859f4d06SJamie Gritton KASSERT(osdm[type].osd_destructors != NULL && 189859f4d06SJamie Gritton (osdm[type].osd_nmethods == 0 || 190859f4d06SJamie Gritton osdm[type].osd_methods != NULL), ("realloc() failed")); 1911ba4a712SPawel Jakub Dawidek OSD_DEBUG("Deregistration of the last slot (type=%u, slot=%u).", 1921ba4a712SPawel Jakub Dawidek type, slot); 1931ba4a712SPawel Jakub Dawidek } else { 1941ba4a712SPawel Jakub Dawidek OSD_DEBUG("Slot deregistration (type=%u, slot=%u).", 1951ba4a712SPawel Jakub Dawidek type, slot); 1961ba4a712SPawel Jakub Dawidek } 197859f4d06SJamie Gritton rm_wunlock(&osdm[type].osd_object_lock); 198859f4d06SJamie Gritton sx_xunlock(&osdm[type].osd_module_lock); 1991ba4a712SPawel Jakub Dawidek } 2001ba4a712SPawel Jakub Dawidek 2011ba4a712SPawel Jakub Dawidek int 2021ba4a712SPawel Jakub Dawidek osd_set(u_int type, struct osd *osd, u_int slot, void *value) 2031ba4a712SPawel Jakub Dawidek { 204320d8421SJamie Gritton 205320d8421SJamie Gritton return (osd_set_reserved(type, osd, slot, NULL, value)); 206320d8421SJamie Gritton } 207320d8421SJamie Gritton 208aa90aec2SConrad Meyer void ** 209320d8421SJamie Gritton osd_reserve(u_int slot) 210320d8421SJamie Gritton { 211320d8421SJamie Gritton 212320d8421SJamie Gritton KASSERT(slot > 0, ("Invalid slot.")); 213320d8421SJamie Gritton 214320d8421SJamie Gritton OSD_DEBUG("Reserving slot array (slot=%u).", slot); 215320d8421SJamie Gritton return (malloc(sizeof(void *) * slot, M_OSD, M_WAITOK | M_ZERO)); 216320d8421SJamie Gritton } 217320d8421SJamie Gritton 218320d8421SJamie Gritton int 219aa90aec2SConrad Meyer osd_set_reserved(u_int type, struct osd *osd, u_int slot, void **rsv, 220320d8421SJamie Gritton void *value) 221320d8421SJamie Gritton { 22261304249SJamie Gritton struct rm_priotracker tracker; 2231ba4a712SPawel Jakub Dawidek 2241ba4a712SPawel Jakub Dawidek KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); 2251ba4a712SPawel Jakub Dawidek KASSERT(slot > 0, ("Invalid slot.")); 2261ba4a712SPawel Jakub Dawidek 227859f4d06SJamie Gritton rm_rlock(&osdm[type].osd_object_lock, &tracker); 228187afc58SMark Johnston KASSERT(osdm[type].osd_destructors[slot - 1] != NULL, ("Unused slot.")); 229187afc58SMark Johnston 23061304249SJamie Gritton if (slot > osd->osd_nslots) { 231aa90aec2SConrad Meyer void **newptr; 232320d8421SJamie Gritton 23361304249SJamie Gritton if (value == NULL) { 23461304249SJamie Gritton OSD_DEBUG( 23561304249SJamie Gritton "Not allocating null slot (type=%u, slot=%u).", 23661304249SJamie Gritton type, slot); 237859f4d06SJamie Gritton rm_runlock(&osdm[type].osd_object_lock, &tracker); 238320d8421SJamie Gritton if (rsv) 239320d8421SJamie Gritton osd_free_reserved(rsv); 24061304249SJamie Gritton return (0); 24161304249SJamie Gritton } 2421ba4a712SPawel Jakub Dawidek 2431ba4a712SPawel Jakub Dawidek /* 244320d8421SJamie Gritton * Too few slots allocated here, so we need to extend or create 24561304249SJamie Gritton * the array. 2461ba4a712SPawel Jakub Dawidek */ 247320d8421SJamie Gritton if (rsv) { 248320d8421SJamie Gritton /* 249320d8421SJamie Gritton * Use the reserve passed in (assumed to be 250320d8421SJamie Gritton * the right size). 251320d8421SJamie Gritton */ 252320d8421SJamie Gritton newptr = rsv; 253320d8421SJamie Gritton if (osd->osd_nslots != 0) { 254320d8421SJamie Gritton memcpy(newptr, osd->osd_slots, 255320d8421SJamie Gritton sizeof(void *) * osd->osd_nslots); 256320d8421SJamie Gritton free(osd->osd_slots, M_OSD); 257320d8421SJamie Gritton } 258320d8421SJamie Gritton } else { 25961304249SJamie Gritton newptr = realloc(osd->osd_slots, sizeof(void *) * slot, 26061304249SJamie Gritton M_OSD, M_NOWAIT | M_ZERO); 26161304249SJamie Gritton if (newptr == NULL) { 262859f4d06SJamie Gritton rm_runlock(&osdm[type].osd_object_lock, 263859f4d06SJamie Gritton &tracker); 2641ba4a712SPawel Jakub Dawidek return (ENOMEM); 26561304249SJamie Gritton } 266320d8421SJamie Gritton } 267320d8421SJamie Gritton if (osd->osd_nslots == 0) { 268320d8421SJamie Gritton /* 269320d8421SJamie Gritton * First OSD for this object, so we need to put it 270320d8421SJamie Gritton * onto the list. 271320d8421SJamie Gritton */ 272320d8421SJamie Gritton mtx_lock(&osdm[type].osd_list_lock); 273320d8421SJamie Gritton LIST_INSERT_HEAD(&osdm[type].osd_list, osd, osd_next); 274320d8421SJamie Gritton mtx_unlock(&osdm[type].osd_list_lock); 275320d8421SJamie Gritton OSD_DEBUG("Setting first slot (type=%u).", type); 276320d8421SJamie Gritton } else 277320d8421SJamie Gritton OSD_DEBUG("Growing slots array (type=%u).", type); 2781ba4a712SPawel Jakub Dawidek osd->osd_slots = newptr; 2791ba4a712SPawel Jakub Dawidek osd->osd_nslots = slot; 280320d8421SJamie Gritton } else if (rsv) 281320d8421SJamie Gritton osd_free_reserved(rsv); 2821ba4a712SPawel Jakub Dawidek OSD_DEBUG("Setting slot value (type=%u, slot=%u, value=%p).", type, 2831ba4a712SPawel Jakub Dawidek slot, value); 2841ba4a712SPawel Jakub Dawidek osd->osd_slots[slot - 1] = value; 285859f4d06SJamie Gritton rm_runlock(&osdm[type].osd_object_lock, &tracker); 2861ba4a712SPawel Jakub Dawidek return (0); 2871ba4a712SPawel Jakub Dawidek } 2881ba4a712SPawel Jakub Dawidek 289320d8421SJamie Gritton void 290aa90aec2SConrad Meyer osd_free_reserved(void **rsv) 291320d8421SJamie Gritton { 292320d8421SJamie Gritton 293320d8421SJamie Gritton OSD_DEBUG("Discarding reserved slot array."); 294320d8421SJamie Gritton free(rsv, M_OSD); 295320d8421SJamie Gritton } 296320d8421SJamie Gritton 2971ba4a712SPawel Jakub Dawidek void * 2981ba4a712SPawel Jakub Dawidek osd_get(u_int type, struct osd *osd, u_int slot) 2991ba4a712SPawel Jakub Dawidek { 30061304249SJamie Gritton struct rm_priotracker tracker; 30161304249SJamie Gritton void *value; 3021ba4a712SPawel Jakub Dawidek 3031ba4a712SPawel Jakub Dawidek KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); 3041ba4a712SPawel Jakub Dawidek KASSERT(slot > 0, ("Invalid slot.")); 3051ba4a712SPawel Jakub Dawidek 306859f4d06SJamie Gritton rm_rlock(&osdm[type].osd_object_lock, &tracker); 307187afc58SMark Johnston KASSERT(osdm[type].osd_destructors[slot - 1] != NULL, ("Unused slot.")); 308187afc58SMark Johnston 3091ba4a712SPawel Jakub Dawidek if (slot > osd->osd_nslots) { 31061304249SJamie Gritton value = NULL; 3111ba4a712SPawel Jakub Dawidek OSD_DEBUG("Slot doesn't exist (type=%u, slot=%u).", type, slot); 31261304249SJamie Gritton } else { 31361304249SJamie Gritton value = osd->osd_slots[slot - 1]; 31461304249SJamie Gritton OSD_DEBUG("Returning slot value (type=%u, slot=%u, value=%p).", 31561304249SJamie Gritton type, slot, value); 3161ba4a712SPawel Jakub Dawidek } 317859f4d06SJamie Gritton rm_runlock(&osdm[type].osd_object_lock, &tracker); 31861304249SJamie Gritton return (value); 3191ba4a712SPawel Jakub Dawidek } 3201ba4a712SPawel Jakub Dawidek 3211ba4a712SPawel Jakub Dawidek void 3221ba4a712SPawel Jakub Dawidek osd_del(u_int type, struct osd *osd, u_int slot) 3231ba4a712SPawel Jakub Dawidek { 32461304249SJamie Gritton struct rm_priotracker tracker; 32561304249SJamie Gritton 326859f4d06SJamie Gritton rm_rlock(&osdm[type].osd_object_lock, &tracker); 32761304249SJamie Gritton do_osd_del(type, osd, slot, 0); 328859f4d06SJamie Gritton rm_runlock(&osdm[type].osd_object_lock, &tracker); 32961304249SJamie Gritton } 33061304249SJamie Gritton 33161304249SJamie Gritton static void 33261304249SJamie Gritton do_osd_del(u_int type, struct osd *osd, u_int slot, int list_locked) 33361304249SJamie Gritton { 3341ba4a712SPawel Jakub Dawidek int i; 3351ba4a712SPawel Jakub Dawidek 3361ba4a712SPawel Jakub Dawidek KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); 3371ba4a712SPawel Jakub Dawidek KASSERT(slot > 0, ("Invalid slot.")); 338859f4d06SJamie Gritton KASSERT(osdm[type].osd_destructors[slot - 1] != NULL, ("Unused slot.")); 3391ba4a712SPawel Jakub Dawidek 3401ba4a712SPawel Jakub Dawidek OSD_DEBUG("Deleting slot (type=%u, slot=%u).", type, slot); 3411ba4a712SPawel Jakub Dawidek 3421ba4a712SPawel Jakub Dawidek if (slot > osd->osd_nslots) { 3431ba4a712SPawel Jakub Dawidek OSD_DEBUG("Slot doesn't exist (type=%u, slot=%u).", type, slot); 3441ba4a712SPawel Jakub Dawidek return; 3451ba4a712SPawel Jakub Dawidek } 3463dd4fac9SJamie Gritton if (osd->osd_slots[slot - 1] != NULL) { 347859f4d06SJamie Gritton osdm[type].osd_destructors[slot - 1](osd->osd_slots[slot - 1]); 3481ba4a712SPawel Jakub Dawidek osd->osd_slots[slot - 1] = NULL; 3493dd4fac9SJamie Gritton } 3501ba4a712SPawel Jakub Dawidek for (i = osd->osd_nslots - 1; i >= 0; i--) { 3511ba4a712SPawel Jakub Dawidek if (osd->osd_slots[i] != NULL) { 35261304249SJamie Gritton OSD_DEBUG("Slot still has a value (type=%u, slot=%u).", 35361304249SJamie Gritton type, i + 1); 3541ba4a712SPawel Jakub Dawidek break; 3551ba4a712SPawel Jakub Dawidek } 3561ba4a712SPawel Jakub Dawidek } 3571ba4a712SPawel Jakub Dawidek if (i == -1) { 3581ba4a712SPawel Jakub Dawidek /* No values left for this object. */ 3591ba4a712SPawel Jakub Dawidek OSD_DEBUG("No more slots left (type=%u).", type); 36061304249SJamie Gritton if (!list_locked) 361859f4d06SJamie Gritton mtx_lock(&osdm[type].osd_list_lock); 3621ba4a712SPawel Jakub Dawidek LIST_REMOVE(osd, osd_next); 36361304249SJamie Gritton if (!list_locked) 364859f4d06SJamie Gritton mtx_unlock(&osdm[type].osd_list_lock); 3651ba4a712SPawel Jakub Dawidek free(osd->osd_slots, M_OSD); 3661ba4a712SPawel Jakub Dawidek osd->osd_slots = NULL; 3671ba4a712SPawel Jakub Dawidek osd->osd_nslots = 0; 3681ba4a712SPawel Jakub Dawidek } else if (slot == osd->osd_nslots) { 3691ba4a712SPawel Jakub Dawidek /* This was the last slot. */ 3701ba4a712SPawel Jakub Dawidek osd->osd_slots = realloc(osd->osd_slots, 3711ba4a712SPawel Jakub Dawidek sizeof(void *) * (i + 1), M_OSD, M_NOWAIT | M_ZERO); 3721ba4a712SPawel Jakub Dawidek /* 3731ba4a712SPawel Jakub Dawidek * We always reallocate to smaller size, so we assume it will 3741ba4a712SPawel Jakub Dawidek * always succeed. 3751ba4a712SPawel Jakub Dawidek */ 3761ba4a712SPawel Jakub Dawidek KASSERT(osd->osd_slots != NULL, ("realloc() failed")); 3771ba4a712SPawel Jakub Dawidek osd->osd_nslots = i + 1; 3781ba4a712SPawel Jakub Dawidek OSD_DEBUG("Reducing slots array to %u (type=%u).", 3791ba4a712SPawel Jakub Dawidek osd->osd_nslots, type); 3801ba4a712SPawel Jakub Dawidek } 3811ba4a712SPawel Jakub Dawidek } 3821ba4a712SPawel Jakub Dawidek 38361304249SJamie Gritton int 38461304249SJamie Gritton osd_call(u_int type, u_int method, void *obj, void *data) 38561304249SJamie Gritton { 38661304249SJamie Gritton osd_method_t methodfun; 38761304249SJamie Gritton int error, i; 38861304249SJamie Gritton 38961304249SJamie Gritton KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); 390859f4d06SJamie Gritton KASSERT(method < osdm[type].osd_nmethods, ("Invalid method.")); 39161304249SJamie Gritton 39261304249SJamie Gritton /* 39361304249SJamie Gritton * Call this method for every slot that defines it, stopping if an 39461304249SJamie Gritton * error is encountered. 39561304249SJamie Gritton */ 39661304249SJamie Gritton error = 0; 397859f4d06SJamie Gritton sx_slock(&osdm[type].osd_module_lock); 398859f4d06SJamie Gritton for (i = 0; i < osdm[type].osd_ntslots; i++) { 399*2bd446d7SKyle Evans /* Hole in the slot map; avoid dereferencing. */ 400*2bd446d7SKyle Evans if (osdm[type].osd_destructors[i] == NULL) 401*2bd446d7SKyle Evans continue; 402859f4d06SJamie Gritton methodfun = osdm[type].osd_methods[i * osdm[type].osd_nmethods + 403859f4d06SJamie Gritton method]; 40461304249SJamie Gritton if (methodfun != NULL && (error = methodfun(obj, data)) != 0) 40561304249SJamie Gritton break; 40661304249SJamie Gritton } 407859f4d06SJamie Gritton sx_sunlock(&osdm[type].osd_module_lock); 40861304249SJamie Gritton return (error); 40961304249SJamie Gritton } 41061304249SJamie Gritton 4111ba4a712SPawel Jakub Dawidek void 4121ba4a712SPawel Jakub Dawidek osd_exit(u_int type, struct osd *osd) 4131ba4a712SPawel Jakub Dawidek { 41461304249SJamie Gritton struct rm_priotracker tracker; 4151ba4a712SPawel Jakub Dawidek u_int i; 4161ba4a712SPawel Jakub Dawidek 4171ba4a712SPawel Jakub Dawidek KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type.")); 4181ba4a712SPawel Jakub Dawidek 4191ba4a712SPawel Jakub Dawidek if (osd->osd_nslots == 0) { 4201ba4a712SPawel Jakub Dawidek KASSERT(osd->osd_slots == NULL, ("Non-null osd_slots.")); 4211ba4a712SPawel Jakub Dawidek /* No OSD attached, just leave. */ 4221ba4a712SPawel Jakub Dawidek return; 4231ba4a712SPawel Jakub Dawidek } 4241ba4a712SPawel Jakub Dawidek 425859f4d06SJamie Gritton rm_rlock(&osdm[type].osd_object_lock, &tracker); 42661304249SJamie Gritton for (i = 1; i <= osd->osd_nslots; i++) { 427859f4d06SJamie Gritton if (osdm[type].osd_destructors[i - 1] != NULL) 42861304249SJamie Gritton do_osd_del(type, osd, i, 0); 42961304249SJamie Gritton else 43061304249SJamie Gritton OSD_DEBUG("Unused slot (type=%u, slot=%u).", type, i); 43161304249SJamie Gritton } 432859f4d06SJamie Gritton rm_runlock(&osdm[type].osd_object_lock, &tracker); 4331ba4a712SPawel Jakub Dawidek OSD_DEBUG("Object exit (type=%u).", type); 4341ba4a712SPawel Jakub Dawidek } 4351ba4a712SPawel Jakub Dawidek 4361ba4a712SPawel Jakub Dawidek static void 4371ba4a712SPawel Jakub Dawidek osd_init(void *arg __unused) 4381ba4a712SPawel Jakub Dawidek { 4391ba4a712SPawel Jakub Dawidek u_int i; 4401ba4a712SPawel Jakub Dawidek 4411ba4a712SPawel Jakub Dawidek for (i = OSD_FIRST; i <= OSD_LAST; i++) { 442859f4d06SJamie Gritton sx_init(&osdm[i].osd_module_lock, "osd_module"); 443859f4d06SJamie Gritton rm_init(&osdm[i].osd_object_lock, "osd_object"); 444859f4d06SJamie Gritton mtx_init(&osdm[i].osd_list_lock, "osd_list", NULL, MTX_DEF); 445859f4d06SJamie Gritton LIST_INIT(&osdm[i].osd_list); 446859f4d06SJamie Gritton osdm[i].osd_destructors = NULL; 447859f4d06SJamie Gritton osdm[i].osd_ntslots = 0; 448859f4d06SJamie Gritton osdm[i].osd_methods = NULL; 4491ba4a712SPawel Jakub Dawidek } 4501ba4a712SPawel Jakub Dawidek } 4511ba4a712SPawel Jakub Dawidek SYSINIT(osd, SI_SUB_LOCK, SI_ORDER_ANY, osd_init, NULL); 452