10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*931Smathue * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate * 260Sstevel@tonic-gate * Inter-Domain Network 270Sstevel@tonic-gate * 280Sstevel@tonic-gate * Shared Memory Region (SMR) supporting code. 290Sstevel@tonic-gate */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <sys/param.h> 350Sstevel@tonic-gate #include <sys/machparam.h> 360Sstevel@tonic-gate #include <sys/debug.h> 370Sstevel@tonic-gate #include <sys/cpuvar.h> 380Sstevel@tonic-gate #include <sys/kmem.h> 390Sstevel@tonic-gate #include <sys/mutex.h> 400Sstevel@tonic-gate #include <sys/rwlock.h> 410Sstevel@tonic-gate #include <sys/systm.h> 420Sstevel@tonic-gate #include <sys/machlock.h> 430Sstevel@tonic-gate #include <sys/membar.h> 440Sstevel@tonic-gate #include <sys/mman.h> 450Sstevel@tonic-gate #include <vm/hat.h> 460Sstevel@tonic-gate #include <vm/as.h> 470Sstevel@tonic-gate #include <vm/hat_sfmmu.h> 480Sstevel@tonic-gate #include <sys/vm_machparam.h> 490Sstevel@tonic-gate #include <sys/x_call.h> 500Sstevel@tonic-gate 510Sstevel@tonic-gate #include <sys/idn.h> 520Sstevel@tonic-gate 530Sstevel@tonic-gate #ifdef DEBUG 540Sstevel@tonic-gate #define DIOCHECK(domid) \ 550Sstevel@tonic-gate { \ 560Sstevel@tonic-gate int _dio; \ 570Sstevel@tonic-gate if ((_dio = idn_domain[domid].dio) < 0) { \ 580Sstevel@tonic-gate cmn_err(CE_WARN, \ 590Sstevel@tonic-gate ">>>>> file %s, line %d: domain %d, dio = %d", \ 600Sstevel@tonic-gate __FILE__, __LINE__, (domid), _dio); \ 610Sstevel@tonic-gate } \ 620Sstevel@tonic-gate } 630Sstevel@tonic-gate #else 640Sstevel@tonic-gate #define DIOCHECK(domid) 650Sstevel@tonic-gate #endif /* DEBUG */ 660Sstevel@tonic-gate 670Sstevel@tonic-gate static int smr_slab_alloc_local(int domid, smr_slab_t **spp); 680Sstevel@tonic-gate static int smr_slab_alloc_remote(int domid, smr_slab_t **spp); 690Sstevel@tonic-gate static void smr_slab_free_local(int domid, smr_slab_t *sp); 700Sstevel@tonic-gate static void smr_slab_free_remote(int domid, smr_slab_t *sp); 710Sstevel@tonic-gate static int smr_slabwaiter_register(int domid); 720Sstevel@tonic-gate static int smr_slabwaiter_unregister(int domid, smr_slab_t **spp); 730Sstevel@tonic-gate static int smr_slaballoc_wait(int domid, smr_slab_t **spp); 740Sstevel@tonic-gate static smr_slab_t *smr_slab_reserve(int domid); 750Sstevel@tonic-gate static void smr_slab_unreserve(int domid, smr_slab_t *sp); 760Sstevel@tonic-gate static void smr_slab_reap_global(); 770Sstevel@tonic-gate 780Sstevel@tonic-gate /* 790Sstevel@tonic-gate * Can only be called by the master. Allocate a slab from the 800Sstevel@tonic-gate * local pool representing the SMR, on behalf of the given 810Sstevel@tonic-gate * domain. Slab is either being requested for use by the 820Sstevel@tonic-gate * local domain (i.e. domid == idn.localid), or it's being 830Sstevel@tonic-gate * allocated to give to a remote domain which requested one. 840Sstevel@tonic-gate * In the base of allocating on behalf of a remote domain, 850Sstevel@tonic-gate * smr_slab_t structure is used simply to manage ownership. 860Sstevel@tonic-gate * 870Sstevel@tonic-gate * Returns: smr_slaballoc_wait 880Sstevel@tonic-gate * (EINVAL, ETIMEDOUT) 890Sstevel@tonic-gate * smr_slabwatier_unregister 900Sstevel@tonic-gate * (0, EINVAL, EBUSY, ENOMEM) 910Sstevel@tonic-gate * ENOLCK 920Sstevel@tonic-gate */ 930Sstevel@tonic-gate static int 940Sstevel@tonic-gate smr_slab_alloc_local(int domid, smr_slab_t **spp) 950Sstevel@tonic-gate { 960Sstevel@tonic-gate int serrno = 0; 970Sstevel@tonic-gate int nwait; 980Sstevel@tonic-gate smr_slab_t *sp; 990Sstevel@tonic-gate idn_domain_t *dp; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate /* 1030Sstevel@tonic-gate * Only the master can make local allocations. 1040Sstevel@tonic-gate */ 1050Sstevel@tonic-gate ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID); 1060Sstevel@tonic-gate ASSERT(idn.localid == IDN_GET_MASTERID()); 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate *spp = NULL; 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate dp = &idn_domain[domid]; 1110Sstevel@tonic-gate ASSERT(DSLAB_READ_HELD(domid)); 1120Sstevel@tonic-gate ASSERT(dp->dslab_state == DSLAB_STATE_LOCAL); 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate /* 1150Sstevel@tonic-gate * Register myself with the waiting list. 1160Sstevel@tonic-gate */ 1170Sstevel@tonic-gate nwait = smr_slabwaiter_register(domid); 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate if (nwait > 1) { 1200Sstevel@tonic-gate /* 1210Sstevel@tonic-gate * XXX - old comment? 1220Sstevel@tonic-gate * Need to drop the read lock _after_ registering 1230Sstevel@tonic-gate * ourselves with the potential wait list for this allocation. 1240Sstevel@tonic-gate * Although this allocation is not a remote one, we could 1250Sstevel@tonic-gate * still have multiple threads on the master trying to 1260Sstevel@tonic-gate * satisfy (allocate) request on behalf of a remote domain. 1270Sstevel@tonic-gate */ 1280Sstevel@tonic-gate /* 1290Sstevel@tonic-gate * Somebody is already in the process of satisfying 1300Sstevel@tonic-gate * the allocation request for this respective 1310Sstevel@tonic-gate * domain. All we need to do is wait and let 1320Sstevel@tonic-gate * it happen. 1330Sstevel@tonic-gate */ 1340Sstevel@tonic-gate serrno = smr_slaballoc_wait(domid, spp); 1350Sstevel@tonic-gate return (serrno); 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate /* 1380Sstevel@tonic-gate * I'm the original slab requester for this domain. It's local 1390Sstevel@tonic-gate * so go ahead and do the job. 1400Sstevel@tonic-gate */ 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate if ((sp = smr_slab_reserve(domid)) == NULL) 1430Sstevel@tonic-gate serrno = ENOMEM; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate /* 1460Sstevel@tonic-gate * Allocation may have failed. In either case we've 1470Sstevel@tonic-gate * got to do the put to at least wake potential waiters up. 1480Sstevel@tonic-gate */ 1490Sstevel@tonic-gate if (!serrno) { 1500Sstevel@tonic-gate if (DSLAB_LOCK_TRYUPGRADE(domid) == 0) { 1510Sstevel@tonic-gate DSLAB_UNLOCK(domid); 1520Sstevel@tonic-gate DSLAB_LOCK_EXCL(domid); 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate } 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate (void) smr_slaballoc_put(domid, sp, 0, serrno); 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate /* 1590Sstevel@tonic-gate * If serrno is ENOLCK here, then we must have failed 1600Sstevel@tonic-gate * on the upgrade above, so lock already dropped. 1610Sstevel@tonic-gate */ 1620Sstevel@tonic-gate if (serrno != ENOLCK) { 1630Sstevel@tonic-gate /* 1640Sstevel@tonic-gate * Need to drop since reaping may be recursive? 1650Sstevel@tonic-gate */ 1660Sstevel@tonic-gate DSLAB_UNLOCK(domid); 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate /* 1700Sstevel@tonic-gate * Since we were the original requester but never went 1710Sstevel@tonic-gate * to sleep, we need to directly unregister ourselves 1720Sstevel@tonic-gate * from the waiting list. 1730Sstevel@tonic-gate */ 1740Sstevel@tonic-gate serrno = smr_slabwaiter_unregister(domid, spp); 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate /* 1770Sstevel@tonic-gate * Now that we've satisfied the request, let's check if any 1780Sstevel@tonic-gate * reaping is necessary. Only the master does this and only 1790Sstevel@tonic-gate * when allocating slabs, an infrequent event :-o 1800Sstevel@tonic-gate */ 1810Sstevel@tonic-gate smr_slab_reap_global(); 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate ASSERT((serrno == 0) ? (*spp != NULL) : (*spp == NULL)); 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate DSLAB_LOCK_SHARED(domid); 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate return (serrno); 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate /* 1910Sstevel@tonic-gate * Can only be called by a slave on behalf of himself. Need to 1920Sstevel@tonic-gate * make a request to the master to allocate a slab of SMR buffers 1930Sstevel@tonic-gate * for the local domain. 1940Sstevel@tonic-gate * 1950Sstevel@tonic-gate * Returns: smr_slaballoc_wait 1960Sstevel@tonic-gate * (0, EINVAL, EBUSY, ENOMEM) 1970Sstevel@tonic-gate * ENOLCK 1980Sstevel@tonic-gate * ECANCELED 1990Sstevel@tonic-gate */ 2000Sstevel@tonic-gate static int 2010Sstevel@tonic-gate smr_slab_alloc_remote(int domid, smr_slab_t **spp) 2020Sstevel@tonic-gate { 2030Sstevel@tonic-gate int nwait; 2040Sstevel@tonic-gate int serrno = 0; 2050Sstevel@tonic-gate int bailout = 0; 2060Sstevel@tonic-gate int masterid; 2070Sstevel@tonic-gate idn_domain_t *dp, *mdp = NULL; 2080Sstevel@tonic-gate procname_t proc = "smr_slab_alloc_remote"; 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* 2110Sstevel@tonic-gate * Only slaves make remote allocations. 2120Sstevel@tonic-gate */ 2130Sstevel@tonic-gate ASSERT(idn.localid != IDN_GET_MASTERID()); 2140Sstevel@tonic-gate ASSERT(domid == idn.localid); 2150Sstevel@tonic-gate ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID); 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate *spp = NULL; 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate dp = &idn_domain[domid]; 2200Sstevel@tonic-gate ASSERT(DSLAB_READ_HELD(domid)); 2210Sstevel@tonic-gate ASSERT(dp->dslab_state == DSLAB_STATE_REMOTE); 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate /* 2240Sstevel@tonic-gate * Register myself with the slaballoc waiting list. 2250Sstevel@tonic-gate * Note that only allow one outstanding allocation 2260Sstevel@tonic-gate * request for the given domain. Other callers which 2270Sstevel@tonic-gate * detect a slab is needed simply get stuck on the 2280Sstevel@tonic-gate * waiting list waiting for the original caller to 2290Sstevel@tonic-gate * get the job done. 2300Sstevel@tonic-gate * The waiter_register routine will allocate the necessary 2310Sstevel@tonic-gate * slab structure which will ultimately be inserted in 2320Sstevel@tonic-gate * the domain's slab list via smr_slaballoc_put(). 2330Sstevel@tonic-gate */ 2340Sstevel@tonic-gate nwait = smr_slabwaiter_register(domid); 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate /* 2370Sstevel@tonic-gate * Make sure we have a connection with the master 2380Sstevel@tonic-gate * before we wait around for nothing and send a 2390Sstevel@tonic-gate * command off to nowhere. 2400Sstevel@tonic-gate * First do a quick (no lock) check for global okayness. 2410Sstevel@tonic-gate */ 2420Sstevel@tonic-gate if ((idn.state != IDNGS_ONLINE) || 2430Sstevel@tonic-gate ((masterid = IDN_GET_MASTERID()) == IDN_NIL_DOMID)) { 2440Sstevel@tonic-gate bailout = 1; 2450Sstevel@tonic-gate serrno = ECANCELED; 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate /* 2480Sstevel@tonic-gate * We need to drop our read lock _before_ acquiring the 2490Sstevel@tonic-gate * slaballoc waiter lock. This is necessary because the 2500Sstevel@tonic-gate * thread that receives the slab alloc response and fills 2510Sstevel@tonic-gate * in the slab structure will need to grab the domain write 2520Sstevel@tonic-gate * lock while holding onto the slaballoc waiter lock. 2530Sstevel@tonic-gate * Potentially could deadlock if we didn't drop our domain 2540Sstevel@tonic-gate * lock before. Plus, we've registered. 2550Sstevel@tonic-gate * 2560Sstevel@tonic-gate * 4093209 - Note also that we do this _after_ the check for 2570Sstevel@tonic-gate * idn.masterid where we grab the READER global 2580Sstevel@tonic-gate * lock. This is to prevent somebody from 2590Sstevel@tonic-gate * changing our state after we drop the drwlock. 2600Sstevel@tonic-gate * A deadlock can occur when shutting down a 2610Sstevel@tonic-gate * domain we're holding the 2620Sstevel@tonic-gate */ 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate if (!bailout) { 2650Sstevel@tonic-gate mdp = &idn_domain[masterid]; 2660Sstevel@tonic-gate /* 2670Sstevel@tonic-gate * Global state is okay. Let's double check the 2680Sstevel@tonic-gate * state of our actual target domain. 2690Sstevel@tonic-gate */ 2700Sstevel@tonic-gate if (mdp->dstate != IDNDS_CONNECTED) { 2710Sstevel@tonic-gate bailout = 1; 2720Sstevel@tonic-gate serrno = ECANCELED; 2730Sstevel@tonic-gate } else if (IDN_DLOCK_TRY_SHARED(masterid)) { 2740Sstevel@tonic-gate if (mdp->dstate != IDNDS_CONNECTED) { 2750Sstevel@tonic-gate bailout = 1; 2760Sstevel@tonic-gate serrno = ECANCELED; 2770Sstevel@tonic-gate IDN_DUNLOCK(masterid); 2780Sstevel@tonic-gate } else if (nwait != 1) { 2790Sstevel@tonic-gate IDN_DUNLOCK(masterid); 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate /* 2820Sstevel@tonic-gate * Note that keep the drwlock(read) for 2830Sstevel@tonic-gate * the target (master) domain if it appears 2840Sstevel@tonic-gate * we're the lucky one to send the command. 2850Sstevel@tonic-gate * We hold onto the lock until we've actually 2860Sstevel@tonic-gate * sent the command out. 2870Sstevel@tonic-gate * We don't reach this place unless it 2880Sstevel@tonic-gate * appears everything is kosher with 2890Sstevel@tonic-gate * the target (master) domain. 2900Sstevel@tonic-gate */ 2910Sstevel@tonic-gate } else { 2920Sstevel@tonic-gate bailout = 1; 2930Sstevel@tonic-gate serrno = ENOLCK; 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate if (bailout) { 2980Sstevel@tonic-gate ASSERT(serrno); 2990Sstevel@tonic-gate /* 3000Sstevel@tonic-gate * Gotta bail. Abort operation. Error result 3010Sstevel@tonic-gate * will be picked up when we attempt to wait. 3020Sstevel@tonic-gate */ 3030Sstevel@tonic-gate PR_SMR("%s: BAILING OUT on behalf domain %d " 3040Sstevel@tonic-gate "(err=%d, gs=%s, ms=%s)\n", 3050Sstevel@tonic-gate proc, domid, serrno, idngs_str[idn.state], 3060Sstevel@tonic-gate (masterid == IDN_NIL_DOMID) 3070Sstevel@tonic-gate ? "unknown" : idnds_str[idn_domain[masterid].dstate]); 3080Sstevel@tonic-gate (void) smr_slabwaiter_abort(domid, serrno); 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate } else if (nwait == 1) { 3110Sstevel@tonic-gate /* 3120Sstevel@tonic-gate * We are the original requester. Initiate the 3130Sstevel@tonic-gate * actual request to the master. 3140Sstevel@tonic-gate */ 3150Sstevel@tonic-gate idn_send_cmd(masterid, IDNCMD_SLABALLOC, 3160Sstevel@tonic-gate IDN_SLAB_SIZE, 0, 0); 3170Sstevel@tonic-gate ASSERT(mdp); 3180Sstevel@tonic-gate IDN_DUNLOCK(masterid); 3190Sstevel@tonic-gate } 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate /* 3220Sstevel@tonic-gate * Wait here for response. Once awakened func returns 3230Sstevel@tonic-gate * with slab structure possibly filled with gifts! 3240Sstevel@tonic-gate */ 3250Sstevel@tonic-gate serrno = smr_slaballoc_wait(domid, spp); 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate return (serrno); 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate /* 3310Sstevel@tonic-gate * Allocate a slab from the Master on behalf 3320Sstevel@tonic-gate * of the given domain. Note that master uses 3330Sstevel@tonic-gate * this function to allocate slabs on behalf of 3340Sstevel@tonic-gate * remote domains also. 3350Sstevel@tonic-gate * Entered with drwlock held. 3360Sstevel@tonic-gate * Leaves with drwlock dropped. 3370Sstevel@tonic-gate * Returns: EDQUOT 3380Sstevel@tonic-gate * EINVAL 3390Sstevel@tonic-gate * ENOLCK 3400Sstevel@tonic-gate * smr_slab_alloc_local 3410Sstevel@tonic-gate * smr_slab_alloc_remote 3420Sstevel@tonic-gate * (0, EINVAL, EBUSY, ENOMEM) 3430Sstevel@tonic-gate */ 3440Sstevel@tonic-gate int 3450Sstevel@tonic-gate smr_slab_alloc(int domid, smr_slab_t **spp) 3460Sstevel@tonic-gate { 3470Sstevel@tonic-gate int serrno = 0; 3480Sstevel@tonic-gate idn_domain_t *dp; 3490Sstevel@tonic-gate procname_t proc = "smr_slab_alloc"; 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate dp = &idn_domain[domid]; 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate ASSERT(DSLAB_READ_HELD(domid)); 3550Sstevel@tonic-gate ASSERT(dp->dslab_state != DSLAB_STATE_UNKNOWN); 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate *spp = NULL; 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate switch (dp->dslab_state) { 3600Sstevel@tonic-gate case DSLAB_STATE_UNKNOWN: 3610Sstevel@tonic-gate cmn_err(CE_WARN, 3620Sstevel@tonic-gate "IDN: 300: no slab allocations without a master"); 3630Sstevel@tonic-gate serrno = EINVAL; 3640Sstevel@tonic-gate break; 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate case DSLAB_STATE_LOCAL: 3670Sstevel@tonic-gate /* 3680Sstevel@tonic-gate * If I'm the master, then get a slab 3690Sstevel@tonic-gate * from the local SMR pool, but only 3700Sstevel@tonic-gate * if the number of allocated slabs has 3710Sstevel@tonic-gate * not been exceeded. 3720Sstevel@tonic-gate */ 3730Sstevel@tonic-gate if (((int)dp->dnslabs < IDN_SLAB_MAXPERDOMAIN) || 3740Sstevel@tonic-gate !IDN_SLAB_MAXPERDOMAIN) 3750Sstevel@tonic-gate serrno = smr_slab_alloc_local(domid, spp); 3760Sstevel@tonic-gate else 3770Sstevel@tonic-gate serrno = EDQUOT; 3780Sstevel@tonic-gate break; 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate case DSLAB_STATE_REMOTE: 3810Sstevel@tonic-gate /* 3820Sstevel@tonic-gate * Have to make a remote request. 3830Sstevel@tonic-gate * In order to prevent overwhelming the master 3840Sstevel@tonic-gate * with a bunch of requests that he won't be able 3850Sstevel@tonic-gate * to handle we do a check to see if we're still 3860Sstevel@tonic-gate * under quota. Note that the limit is known 3870Sstevel@tonic-gate * apriori based on the SMR/NWR size and 3880Sstevel@tonic-gate * IDN_SLAB_MINTOTAL. Domains must have the same 3890Sstevel@tonic-gate * size SMR/NWR, however they can have different 3900Sstevel@tonic-gate * IDN_SLAB_MINTOTAL. Thus a domain could throttle 3910Sstevel@tonic-gate * itself however it wishes. 3920Sstevel@tonic-gate */ 3930Sstevel@tonic-gate if (((int)dp->dnslabs < IDN_SLAB_MAXPERDOMAIN) || 3940Sstevel@tonic-gate !IDN_SLAB_MAXPERDOMAIN) 3950Sstevel@tonic-gate serrno = smr_slab_alloc_remote(domid, spp); 3960Sstevel@tonic-gate else 3970Sstevel@tonic-gate serrno = EDQUOT; 3980Sstevel@tonic-gate break; 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate default: 4010Sstevel@tonic-gate cmn_err(CE_WARN, 4020Sstevel@tonic-gate "IDN: 301: (ALLOC) unknown slab state (%d) " 4030Sstevel@tonic-gate "for domain %d", dp->dslab_state, domid); 4040Sstevel@tonic-gate serrno = EINVAL; 4050Sstevel@tonic-gate break; 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate if (*spp == NULL) { 4090Sstevel@tonic-gate PR_SMR("%s: failed to allocate %s slab [serrno = %d]\n", 4100Sstevel@tonic-gate proc, (idn.localid == IDN_GET_MASTERID()) ? 4110Sstevel@tonic-gate "local" : "remote", serrno); 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate if (serrno) { 4150Sstevel@tonic-gate IDN_GKSTAT_GLOBAL_EVENT(gk_slabfail, gk_slabfail_last); 4160Sstevel@tonic-gate } 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate return (serrno); 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate static void 4220Sstevel@tonic-gate smr_slab_free_local(int domid, smr_slab_t *sp) 4230Sstevel@tonic-gate { 4240Sstevel@tonic-gate int rv; 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate /* 4270Sstevel@tonic-gate * Do a slaballoc_put just in case there may have 4280Sstevel@tonic-gate * been waiters for slabs for this respective domain 4290Sstevel@tonic-gate * before we unreserve this slab. 4300Sstevel@tonic-gate */ 4310Sstevel@tonic-gate rv = smr_slaballoc_put(domid, sp, 0, 0); 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate if (rv == -1) { 4340Sstevel@tonic-gate /* 4350Sstevel@tonic-gate * Put failed. Must not have been any waiters. 4360Sstevel@tonic-gate * Go ahead and unreserve the space. 4370Sstevel@tonic-gate */ 4380Sstevel@tonic-gate smr_slab_unreserve(domid, sp); 4390Sstevel@tonic-gate } 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate static void 4430Sstevel@tonic-gate smr_slab_free_remote(int domid, smr_slab_t *sp) 4440Sstevel@tonic-gate { 4450Sstevel@tonic-gate smr_offset_t slab_offset; 4460Sstevel@tonic-gate int slab_size; 4470Sstevel@tonic-gate int rv; 4480Sstevel@tonic-gate int masterid; 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate ASSERT(domid == idn.localid); 4510Sstevel@tonic-gate ASSERT(idn.localid != IDN_GET_MASTERID()); 4520Sstevel@tonic-gate ASSERT(DSLAB_WRITE_HELD(domid)); 4530Sstevel@tonic-gate ASSERT(idn_domain[domid].dslab_state == DSLAB_STATE_REMOTE); 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate masterid = IDN_GET_MASTERID(); 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate ASSERT(masterid != IDN_NIL_DOMID); 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate slab_offset = IDN_ADDR2OFFSET(sp->sl_start); 4600Sstevel@tonic-gate slab_size = (int)(sp->sl_end - sp->sl_start); 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate /* 4630Sstevel@tonic-gate * Do a slaballoc_put just in case there may have 4640Sstevel@tonic-gate * been waiters for slabs for this domain before 4650Sstevel@tonic-gate * returning back to the master. 4660Sstevel@tonic-gate */ 4670Sstevel@tonic-gate rv = smr_slaballoc_put(domid, sp, 0, 0); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate if ((rv == -1) && (masterid != IDN_NIL_DOMID)) { 4700Sstevel@tonic-gate /* 4710Sstevel@tonic-gate * Put failed. No waiters so free the local data 4720Sstevel@tonic-gate * structure ship the SMR range off to the master. 4730Sstevel@tonic-gate */ 4740Sstevel@tonic-gate smr_free_buflist(sp); 4750Sstevel@tonic-gate FREESTRUCT(sp, smr_slab_t, 1); 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate IDN_DLOCK_SHARED(masterid); 4780Sstevel@tonic-gate idn_send_cmd(masterid, IDNCMD_SLABFREE, 4790Sstevel@tonic-gate slab_offset, slab_size, 0); 4800Sstevel@tonic-gate IDN_DUNLOCK(masterid); 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate /* 4850Sstevel@tonic-gate * Free up the list of slabs passed 4860Sstevel@tonic-gate */ 4870Sstevel@tonic-gate void 4880Sstevel@tonic-gate smr_slab_free(int domid, smr_slab_t *sp) 4890Sstevel@tonic-gate { 4900Sstevel@tonic-gate smr_slab_t *nsp = NULL; 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate ASSERT(DSLAB_WRITE_HELD(domid)); 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate if (sp == NULL) 4950Sstevel@tonic-gate return; 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID); 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate switch (idn_domain[domid].dslab_state) { 5000Sstevel@tonic-gate case DSLAB_STATE_UNKNOWN: 5010Sstevel@tonic-gate cmn_err(CE_WARN, 5020Sstevel@tonic-gate "IDN: 302: no slab free without a master"); 5030Sstevel@tonic-gate break; 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate case DSLAB_STATE_LOCAL: 5060Sstevel@tonic-gate /* 5070Sstevel@tonic-gate * If I'm the master then put the slabs 5080Sstevel@tonic-gate * back to the local SMR pool. 5090Sstevel@tonic-gate */ 5100Sstevel@tonic-gate for (; sp; sp = nsp) { 5110Sstevel@tonic-gate nsp = sp->sl_next; 5120Sstevel@tonic-gate smr_slab_free_local(domid, sp); 5130Sstevel@tonic-gate } 5140Sstevel@tonic-gate break; 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate case DSLAB_STATE_REMOTE: 5170Sstevel@tonic-gate /* 5180Sstevel@tonic-gate * If the domid is my own then I'm freeing 5190Sstevel@tonic-gate * a slab back to the Master. 5200Sstevel@tonic-gate */ 5210Sstevel@tonic-gate for (; sp; sp = nsp) { 5220Sstevel@tonic-gate nsp = sp->sl_next; 5230Sstevel@tonic-gate smr_slab_free_remote(domid, sp); 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate break; 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate default: 5280Sstevel@tonic-gate cmn_err(CE_WARN, 5290Sstevel@tonic-gate "IDN: 301: (FREE) unknown slab state " 5300Sstevel@tonic-gate "(%d) for domain %d", 5310Sstevel@tonic-gate idn_domain[domid].dslab_state, domid); 5320Sstevel@tonic-gate break; 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate } 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate /* 5370Sstevel@tonic-gate * Free up the list of slab data structures ONLY. 5380Sstevel@tonic-gate * This is called during a fatal shutdown of the master 5390Sstevel@tonic-gate * where we need to garbage collect the locally allocated 5400Sstevel@tonic-gate * data structures used to manage slabs allocated to the 5410Sstevel@tonic-gate * local domain. Should never be called by a master since 5420Sstevel@tonic-gate * the master can do a regular smr_slab_free. 5430Sstevel@tonic-gate */ 5440Sstevel@tonic-gate void 5450Sstevel@tonic-gate smr_slab_garbage_collection(smr_slab_t *sp) 5460Sstevel@tonic-gate { 5470Sstevel@tonic-gate smr_slab_t *nsp; 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate ASSERT(idn_domain[idn.localid].dvote.v.master == 0); 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate if (sp == NULL) 5520Sstevel@tonic-gate return; 5530Sstevel@tonic-gate /* 5540Sstevel@tonic-gate * Since this is only ever called by a slave, 5550Sstevel@tonic-gate * the slab structure size always contains a buflist. 5560Sstevel@tonic-gate */ 5570Sstevel@tonic-gate for (; sp; sp = nsp) { 5580Sstevel@tonic-gate nsp = sp->sl_next; 5590Sstevel@tonic-gate smr_free_buflist(sp); 5600Sstevel@tonic-gate FREESTRUCT(sp, smr_slab_t, 1); 5610Sstevel@tonic-gate } 5620Sstevel@tonic-gate } 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate /* 5650Sstevel@tonic-gate * Allocate a SMR buffer on behalf of the local domain 5660Sstevel@tonic-gate * which is ultimately targeted for the given domain. 5670Sstevel@tonic-gate * 5680Sstevel@tonic-gate * IMPORTANT: This routine is going to drop the domain rwlock (drwlock) 5690Sstevel@tonic-gate * for the domain on whose behalf the request is being 5700Sstevel@tonic-gate * made. This routine canNOT block on trying to 5710Sstevel@tonic-gate * reacquire the drwlock. If he does block then somebody 5720Sstevel@tonic-gate * must have the write lock on the domain which most likely 5730Sstevel@tonic-gate * means the domain is going south anyway, so just bail on 5740Sstevel@tonic-gate * this buffer. Higher levels will retry if needed. 5750Sstevel@tonic-gate * 5760Sstevel@tonic-gate * XXX - Support larger than IDN_SMR_BUFSIZE allocations? 5770Sstevel@tonic-gate * 5780Sstevel@tonic-gate * Returns: A negative return value indicates lock lost on domid. 5790Sstevel@tonic-gate * EINVAL, ENOLINK, ENOLCK(internal) 5800Sstevel@tonic-gate * smr_slaballoc_wait 5810Sstevel@tonic-gate * (EINVAL, ETIMEDOUT) 5820Sstevel@tonic-gate * smr_slabwatier_unregister 5830Sstevel@tonic-gate * (0, EINVAL, EBUSY, ENOMEM) 5840Sstevel@tonic-gate */ 5850Sstevel@tonic-gate int 5860Sstevel@tonic-gate smr_buf_alloc(int domid, uint_t len, caddr_t *bufpp) 5870Sstevel@tonic-gate { 5880Sstevel@tonic-gate register idn_domain_t *dp, *ldp; 5890Sstevel@tonic-gate smr_slab_t *sp; 5900Sstevel@tonic-gate caddr_t bufp = NULL; 5910Sstevel@tonic-gate int serrno; 5920Sstevel@tonic-gate procname_t proc = "smr_buf_alloc"; 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate dp = &idn_domain[domid]; 5950Sstevel@tonic-gate /* 5960Sstevel@tonic-gate * Local domain can only allocate on behalf of 5970Sstevel@tonic-gate * itself if this is a priviledged call and the 5980Sstevel@tonic-gate * caller is the master. 5990Sstevel@tonic-gate */ 6000Sstevel@tonic-gate ASSERT((domid != idn.localid) && (domid != IDN_NIL_DOMID)); 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate *bufpp = NULL; 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate if (len > IDN_DATA_SIZE) { 6050Sstevel@tonic-gate cmn_err(CE_WARN, 606*931Smathue "IDN: 303: buffer len %d > IDN_DATA_SIZE (%lu)", 6070Sstevel@tonic-gate len, IDN_DATA_SIZE); 6080Sstevel@tonic-gate IDN_GKSTAT_GLOBAL_EVENT(gk_buffail, gk_buffail_last); 6090Sstevel@tonic-gate return (EINVAL); 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate /* 6130Sstevel@tonic-gate * Need to go to my local slab list to find 6140Sstevel@tonic-gate * a buffer. 6150Sstevel@tonic-gate */ 6160Sstevel@tonic-gate ldp = &idn_domain[idn.localid]; 6170Sstevel@tonic-gate /* 6180Sstevel@tonic-gate * Now we loop trying to locate a buffer out of our 6190Sstevel@tonic-gate * slabs. We continue this until either we find a 6200Sstevel@tonic-gate * buffer or we're unable to allocate a slab. Note 6210Sstevel@tonic-gate * that new slabs are allocated to the front. 6220Sstevel@tonic-gate */ 6230Sstevel@tonic-gate DSLAB_LOCK_SHARED(idn.localid); 6240Sstevel@tonic-gate sp = ldp->dslab; 6250Sstevel@tonic-gate do { 6260Sstevel@tonic-gate int spl, all_empty; 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate if (sp == NULL) { 6290Sstevel@tonic-gate if ((serrno = smr_slab_alloc(idn.localid, &sp)) != 0) { 6300Sstevel@tonic-gate PR_SMR("%s:%d: failed to allocate " 6310Sstevel@tonic-gate "slab [serrno = %d]", 6320Sstevel@tonic-gate proc, domid, serrno); 6330Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid); 6340Sstevel@tonic-gate IDN_GKSTAT_GLOBAL_EVENT(gk_buffail, 6350Sstevel@tonic-gate gk_buffail_last); 6360Sstevel@tonic-gate return (serrno); 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate /* 6390Sstevel@tonic-gate * Of course, the world may have changed while 6400Sstevel@tonic-gate * we dropped the lock. Better make sure we're 6410Sstevel@tonic-gate * still established. 6420Sstevel@tonic-gate */ 6430Sstevel@tonic-gate if (dp->dstate != IDNDS_CONNECTED) { 6440Sstevel@tonic-gate PR_SMR("%s:%d: state changed during slab " 6450Sstevel@tonic-gate "alloc (dstate = %s)\n", 6460Sstevel@tonic-gate proc, domid, idnds_str[dp->dstate]); 6470Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid); 6480Sstevel@tonic-gate IDN_GKSTAT_GLOBAL_EVENT(gk_buffail, 6490Sstevel@tonic-gate gk_buffail_last); 6500Sstevel@tonic-gate return (ENOLINK); 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate /* 6530Sstevel@tonic-gate * We were able to allocate a slab. Should 6540Sstevel@tonic-gate * be at the front of the list, spin again. 6550Sstevel@tonic-gate */ 6560Sstevel@tonic-gate sp = ldp->dslab; 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate /* 6590Sstevel@tonic-gate * If we have reached here then we have a slab! 6600Sstevel@tonic-gate * Hopefully there are free bufs there :-o 6610Sstevel@tonic-gate */ 6620Sstevel@tonic-gate spl = splhi(); 6630Sstevel@tonic-gate all_empty = 1; 6640Sstevel@tonic-gate for (; sp && !bufp; sp = sp->sl_next) { 6650Sstevel@tonic-gate smr_slabbuf_t *bp; 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate if (sp->sl_free == NULL) 6680Sstevel@tonic-gate continue; 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate if (!lock_try(&sp->sl_lock)) { 6710Sstevel@tonic-gate all_empty = 0; 6720Sstevel@tonic-gate continue; 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate if ((bp = sp->sl_free) == NULL) { 6760Sstevel@tonic-gate lock_clear(&sp->sl_lock); 6770Sstevel@tonic-gate continue; 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate sp->sl_free = bp->sb_next; 6810Sstevel@tonic-gate bp->sb_next = sp->sl_inuse; 6820Sstevel@tonic-gate sp->sl_inuse = bp; 6830Sstevel@tonic-gate /* 6840Sstevel@tonic-gate * Found a free buffer. 6850Sstevel@tonic-gate */ 6860Sstevel@tonic-gate bp->sb_domid = domid; 6870Sstevel@tonic-gate bufp = bp->sb_bufp; 6880Sstevel@tonic-gate lock_clear(&sp->sl_lock); 6890Sstevel@tonic-gate } 6900Sstevel@tonic-gate splx(spl); 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate if (!all_empty && !bufp) { 6930Sstevel@tonic-gate /* 6940Sstevel@tonic-gate * If we still haven't found a buffer, but 6950Sstevel@tonic-gate * there's still possibly a buffer available, 6960Sstevel@tonic-gate * then try again. Only if we're absolutely 6970Sstevel@tonic-gate * sure all slabs are empty do we attempt 6980Sstevel@tonic-gate * to allocate a new one. 6990Sstevel@tonic-gate */ 7000Sstevel@tonic-gate sp = ldp->dslab; 7010Sstevel@tonic-gate } 7020Sstevel@tonic-gate } while (bufp == NULL); 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate *bufpp = bufp; 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate ATOMIC_INC(dp->dio); 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid); 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate return (0); 7110Sstevel@tonic-gate } 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate /* 7140Sstevel@tonic-gate * Free a buffer allocated to the local domain back to 7150Sstevel@tonic-gate * its respective slab. Slabs are freed via the slab-reap command. 7160Sstevel@tonic-gate * XXX - Support larger than IDN_SMR_BUFSIZE allocations? 7170Sstevel@tonic-gate */ 7180Sstevel@tonic-gate int 7190Sstevel@tonic-gate smr_buf_free(int domid, caddr_t bufp, uint_t len) 7200Sstevel@tonic-gate { 7210Sstevel@tonic-gate register smr_slab_t *sp; 7220Sstevel@tonic-gate smr_slabbuf_t *bp, **bpp; 7230Sstevel@tonic-gate idn_domain_t *ldp; 7240Sstevel@tonic-gate int buffreed; 7250Sstevel@tonic-gate int lockheld = (len == (uint_t)-1); 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate /* 7280Sstevel@tonic-gate * We should never be free'ing a buffer on 7290Sstevel@tonic-gate * behalf of ourselves as we are never the 7300Sstevel@tonic-gate * target for allocated SMR buffers. 7310Sstevel@tonic-gate */ 7320Sstevel@tonic-gate ASSERT(domid != idn.localid); 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate sp = NULL; 7350Sstevel@tonic-gate buffreed = 0; 7360Sstevel@tonic-gate ldp = &idn_domain[idn.localid]; 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate DSLAB_LOCK_SHARED(idn.localid); 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate if (((uintptr_t)bufp & (IDN_SMR_BUFSIZE-1)) && 7410Sstevel@tonic-gate (IDN_ADDR2OFFSET(bufp) % IDN_SMR_BUFSIZE)) { 7420Sstevel@tonic-gate cmn_err(CE_WARN, 743*931Smathue "IDN: 304: buffer (0x%p) from domain %d not on a " 744*931Smathue "%d boundary", bufp, domid, IDN_SMR_BUFSIZE); 7450Sstevel@tonic-gate goto bfdone; 7460Sstevel@tonic-gate } 7470Sstevel@tonic-gate if (!lockheld && (len > IDN_DATA_SIZE)) { 7480Sstevel@tonic-gate cmn_err(CE_WARN, 7490Sstevel@tonic-gate "IDN: 305: buffer length (%d) from domain %d greater " 750*931Smathue "than IDN_DATA_SIZE (%lu)", 7510Sstevel@tonic-gate len, domid, IDN_DATA_SIZE); 7520Sstevel@tonic-gate goto bfdone; 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate for (sp = ldp->dslab; sp; sp = sp->sl_next) 7560Sstevel@tonic-gate if ((bufp >= sp->sl_start) && (bufp < sp->sl_end)) 7570Sstevel@tonic-gate break; 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate if (sp) { 7600Sstevel@tonic-gate int spl; 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate spl = splhi(); 7630Sstevel@tonic-gate while (!lock_try(&sp->sl_lock)) 7640Sstevel@tonic-gate ; 7650Sstevel@tonic-gate bpp = &sp->sl_inuse; 7660Sstevel@tonic-gate for (bp = *bpp; bp; bp = *bpp) { 7670Sstevel@tonic-gate if (bp->sb_bufp == bufp) 7680Sstevel@tonic-gate break; 7690Sstevel@tonic-gate bpp = &bp->sb_next; 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate if (bp) { 7720Sstevel@tonic-gate ASSERT(bp->sb_domid == domid); 7730Sstevel@tonic-gate buffreed++; 7740Sstevel@tonic-gate bp->sb_domid = IDN_NIL_DOMID; 7750Sstevel@tonic-gate *bpp = bp->sb_next; 7760Sstevel@tonic-gate bp->sb_next = sp->sl_free; 7770Sstevel@tonic-gate sp->sl_free = bp; 7780Sstevel@tonic-gate } 7790Sstevel@tonic-gate lock_clear(&sp->sl_lock); 7800Sstevel@tonic-gate splx(spl); 7810Sstevel@tonic-gate } 7820Sstevel@tonic-gate bfdone: 7830Sstevel@tonic-gate if (buffreed) { 7840Sstevel@tonic-gate ATOMIC_DEC(idn_domain[domid].dio); 7850Sstevel@tonic-gate DIOCHECK(domid); 7860Sstevel@tonic-gate } else { 7870Sstevel@tonic-gate cmn_err(CE_WARN, 7880Sstevel@tonic-gate "IDN: 306: unknown buffer (0x%p) from domain %d", 7890Sstevel@tonic-gate bufp, domid); 7900Sstevel@tonic-gate ATOMIC_INC(idn_domain[domid].dioerr); 7910Sstevel@tonic-gate } 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid); 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate return (sp ? 0 : -1); 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate /* 7990Sstevel@tonic-gate * Alternative interface to smr_buf_free, but with local drwlock 8000Sstevel@tonic-gate * held. 8010Sstevel@tonic-gate */ 8020Sstevel@tonic-gate /* ARGSUSED2 */ 8030Sstevel@tonic-gate int 8040Sstevel@tonic-gate smr_buf_free_locked(int domid, caddr_t bufp, uint_t len) 8050Sstevel@tonic-gate { 8060Sstevel@tonic-gate return (smr_buf_free(domid, bufp, (uint_t)-1)); 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate /* 8100Sstevel@tonic-gate * Free any and all buffers associated with the given domain. 8110Sstevel@tonic-gate * Assumption is that domain is dead and buffers are not in use. 8120Sstevel@tonic-gate * Returns: Number of buffers freed. 8130Sstevel@tonic-gate * -1 if error. 8140Sstevel@tonic-gate */ 8150Sstevel@tonic-gate int 8160Sstevel@tonic-gate smr_buf_free_all(int domid) 8170Sstevel@tonic-gate { 8180Sstevel@tonic-gate register smr_slab_t *sp; 8190Sstevel@tonic-gate register smr_slabbuf_t *bp, **bpp; 8200Sstevel@tonic-gate idn_domain_t *ldp; 8210Sstevel@tonic-gate int nbufsfreed = 0; 8220Sstevel@tonic-gate procname_t proc = "smr_buf_free_all"; 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate /* 8250Sstevel@tonic-gate * We should never be free'ing buffers on 8260Sstevel@tonic-gate * behalf of ourself 8270Sstevel@tonic-gate */ 8280Sstevel@tonic-gate ASSERT(domid != idn.localid); 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate if (!VALID_DOMAINID(domid)) { 8310Sstevel@tonic-gate cmn_err(CE_WARN, 832*931Smathue "IDN: 307: domain ID (%d) invalid", domid); 8330Sstevel@tonic-gate return (-1); 8340Sstevel@tonic-gate } 8350Sstevel@tonic-gate 8360Sstevel@tonic-gate ldp = &idn_domain[idn.localid]; 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate /* 8390Sstevel@tonic-gate * We grab the writer lock so that we don't have any 8400Sstevel@tonic-gate * competition during a "free-all" call. 8410Sstevel@tonic-gate * No need to grab individual slab locks when holding 8420Sstevel@tonic-gate * dslab(writer). 8430Sstevel@tonic-gate */ 8440Sstevel@tonic-gate DSLAB_LOCK_EXCL(idn.localid); 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate for (sp = ldp->dslab; sp; sp = sp->sl_next) { 8470Sstevel@tonic-gate bpp = &sp->sl_inuse; 8480Sstevel@tonic-gate for (bp = *bpp; bp; bp = *bpp) { 8490Sstevel@tonic-gate if (bp->sb_domid == domid) { 8500Sstevel@tonic-gate bp->sb_domid = IDN_NIL_DOMID; 8510Sstevel@tonic-gate *bpp = bp->sb_next; 8520Sstevel@tonic-gate bp->sb_next = sp->sl_free; 8530Sstevel@tonic-gate sp->sl_free = bp; 8540Sstevel@tonic-gate nbufsfreed++; 8550Sstevel@tonic-gate } else { 8560Sstevel@tonic-gate bpp = &bp->sb_next; 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate } 8590Sstevel@tonic-gate } 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate if (nbufsfreed > 0) { 8620Sstevel@tonic-gate ATOMIC_SUB(idn_domain[domid].dio, nbufsfreed); 8630Sstevel@tonic-gate idn_domain[domid].dioerr = 0; 8640Sstevel@tonic-gate DIOCHECK(domid); 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid); 8680Sstevel@tonic-gate 8690Sstevel@tonic-gate PR_SMR("%s: freed %d buffers for domain %d\n", 8700Sstevel@tonic-gate proc, nbufsfreed, domid); 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate return (nbufsfreed); 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate int 8760Sstevel@tonic-gate smr_buf_reclaim(int domid, int nbufs) 8770Sstevel@tonic-gate { 8780Sstevel@tonic-gate int num_reclaimed = 0; 8790Sstevel@tonic-gate idn_domain_t *ldp, *dp; 8800Sstevel@tonic-gate procname_t proc = "smr_buf_reclaim"; 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate ldp = &idn_domain[idn.localid]; 8830Sstevel@tonic-gate dp = &idn_domain[domid]; 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate ASSERT(domid != idn.localid); 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate if (ATOMIC_CAS(&dp->dreclaim_inprogress, 0, 1)) { 8880Sstevel@tonic-gate /* 8890Sstevel@tonic-gate * Reclaim is already in progress, don't 8900Sstevel@tonic-gate * bother. 8910Sstevel@tonic-gate */ 8920Sstevel@tonic-gate PR_DATA("%s: reclaim already in progress\n", proc); 8930Sstevel@tonic-gate return (0); 8940Sstevel@tonic-gate } 8950Sstevel@tonic-gate 8960Sstevel@tonic-gate PR_SMR("%s: requested %d buffers from domain %d\n", 8970Sstevel@tonic-gate proc, nbufs, domid); 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate if (dp->dio && nbufs) { 9000Sstevel@tonic-gate register smr_slab_t *sp; 9010Sstevel@tonic-gate int spl; 9020Sstevel@tonic-gate 9030Sstevel@tonic-gate DSLAB_LOCK_SHARED(idn.localid); 9040Sstevel@tonic-gate spl = splhi(); 9050Sstevel@tonic-gate for (sp = ldp->dslab; sp && nbufs; sp = sp->sl_next) { 9060Sstevel@tonic-gate register smr_slabbuf_t *bp, **bpp; 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate if (sp->sl_inuse == NULL) 9090Sstevel@tonic-gate continue; 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate if (!lock_try(&sp->sl_lock)) 9120Sstevel@tonic-gate continue; 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate if (sp->sl_inuse == NULL) { 9150Sstevel@tonic-gate lock_clear(&sp->sl_lock); 9160Sstevel@tonic-gate continue; 9170Sstevel@tonic-gate } 9180Sstevel@tonic-gate 9190Sstevel@tonic-gate bpp = &sp->sl_inuse; 9200Sstevel@tonic-gate for (bp = *bpp; bp && nbufs; bp = *bpp) { 9210Sstevel@tonic-gate if (bp->sb_domid == domid) { 9220Sstevel@tonic-gate /* 9230Sstevel@tonic-gate * Buffer no longer in use, 9240Sstevel@tonic-gate * reclaim it. 9250Sstevel@tonic-gate */ 9260Sstevel@tonic-gate bp->sb_domid = IDN_NIL_DOMID; 9270Sstevel@tonic-gate *bpp = bp->sb_next; 9280Sstevel@tonic-gate bp->sb_next = sp->sl_free; 9290Sstevel@tonic-gate sp->sl_free = bp; 9300Sstevel@tonic-gate num_reclaimed++; 9310Sstevel@tonic-gate nbufs--; 9320Sstevel@tonic-gate } else { 9330Sstevel@tonic-gate bpp = &bp->sb_next; 9340Sstevel@tonic-gate } 9350Sstevel@tonic-gate } 9360Sstevel@tonic-gate lock_clear(&sp->sl_lock); 9370Sstevel@tonic-gate } 9380Sstevel@tonic-gate splx(spl); 9390Sstevel@tonic-gate 9400Sstevel@tonic-gate if (num_reclaimed > 0) { 9410Sstevel@tonic-gate ATOMIC_SUB(dp->dio, num_reclaimed); 9420Sstevel@tonic-gate DIOCHECK(domid); 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid); 9450Sstevel@tonic-gate } 9460Sstevel@tonic-gate 9470Sstevel@tonic-gate PR_SMR("%s: reclaimed %d buffers from domain %d\n", 9480Sstevel@tonic-gate proc, num_reclaimed, domid); 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate return (num_reclaimed); 9510Sstevel@tonic-gate } 9520Sstevel@tonic-gate 9530Sstevel@tonic-gate /* 9540Sstevel@tonic-gate * Returns 1 If any buffers are locked for the given slab. 9550Sstevel@tonic-gate * 0 If all buffers are free for the given slab. 9560Sstevel@tonic-gate * 9570Sstevel@tonic-gate * The caller is assumed to have the slab protected so that no 9580Sstevel@tonic-gate * new allocations are attempted from it. Also, this is only 9590Sstevel@tonic-gate * valid to be called with respect to slabs that were allocated 9600Sstevel@tonic-gate * on behalf of the local domain, i.e. the master is not expected 9610Sstevel@tonic-gate * to call this function with (slave) slab "representatives". 9620Sstevel@tonic-gate */ 9630Sstevel@tonic-gate int 9640Sstevel@tonic-gate smr_slab_busy(smr_slab_t *sp) 9650Sstevel@tonic-gate { 9660Sstevel@tonic-gate return ((sp && sp->sl_inuse) ? 1 : 0); 9670Sstevel@tonic-gate } 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate int 9700Sstevel@tonic-gate smr_slabwaiter_init() 9710Sstevel@tonic-gate { 9720Sstevel@tonic-gate register int i; 9730Sstevel@tonic-gate struct slabwaiter *wp; 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate if (idn.slabwaiter != NULL) 9760Sstevel@tonic-gate return (0); 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate /* 9790Sstevel@tonic-gate * Initialize the slab waiting area for MAX_DOMAINS. 9800Sstevel@tonic-gate */ 9810Sstevel@tonic-gate idn.slabwaiter = GETSTRUCT(struct slabwaiter, MAX_DOMAINS); 9820Sstevel@tonic-gate wp = idn.slabwaiter; 9830Sstevel@tonic-gate for (i = 0; i < MAX_DOMAINS; wp++, i++) { 9840Sstevel@tonic-gate wp->w_closed = 0; 9850Sstevel@tonic-gate mutex_init(&wp->w_mutex, NULL, MUTEX_DEFAULT, NULL); 9860Sstevel@tonic-gate cv_init(&wp->w_cv, NULL, CV_DEFAULT, NULL); 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate return (0); 9900Sstevel@tonic-gate } 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate void 9930Sstevel@tonic-gate smr_slabwaiter_deinit() 9940Sstevel@tonic-gate { 9950Sstevel@tonic-gate register int i; 9960Sstevel@tonic-gate struct slabwaiter *wp; 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate if ((wp = idn.slabwaiter) == NULL) 9990Sstevel@tonic-gate return; 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate for (i = 0; i < MAX_DOMAINS; wp++, i++) { 10020Sstevel@tonic-gate ASSERT(wp->w_nwaiters == 0); 10030Sstevel@tonic-gate ASSERT(wp->w_sp == NULL); 10040Sstevel@tonic-gate cv_destroy(&wp->w_cv); 10050Sstevel@tonic-gate mutex_destroy(&wp->w_mutex); 10060Sstevel@tonic-gate } 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate FREESTRUCT(idn.slabwaiter, struct slabwaiter, MAX_DOMAINS); 10090Sstevel@tonic-gate idn.slabwaiter = NULL; 10100Sstevel@tonic-gate } 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate void 10130Sstevel@tonic-gate smr_slabwaiter_open(domainset_t domset) 10140Sstevel@tonic-gate { 10150Sstevel@tonic-gate int d; 10160Sstevel@tonic-gate struct slabwaiter *wp; 10170Sstevel@tonic-gate 10180Sstevel@tonic-gate if ((domset == 0) || !idn.slabwaiter) 10190Sstevel@tonic-gate return; 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate wp = idn.slabwaiter; 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate for (d = 0; d < MAX_DOMAINS; wp++, d++) { 10240Sstevel@tonic-gate if (!DOMAIN_IN_SET(domset, d)) 10250Sstevel@tonic-gate continue; 10260Sstevel@tonic-gate mutex_enter(&wp->w_mutex); 10270Sstevel@tonic-gate wp->w_closed = 0; 10280Sstevel@tonic-gate mutex_exit(&wp->w_mutex); 10290Sstevel@tonic-gate } 10300Sstevel@tonic-gate } 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate void 10330Sstevel@tonic-gate smr_slabwaiter_close(domainset_t domset) 10340Sstevel@tonic-gate { 10350Sstevel@tonic-gate int d; 10360Sstevel@tonic-gate struct slabwaiter *wp; 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate if ((domset == 0) || !idn.slabwaiter) 10390Sstevel@tonic-gate return; 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate wp = idn.slabwaiter; 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate for (d = 0; d < MAX_DOMAINS; wp++, d++) { 10440Sstevel@tonic-gate if (!DOMAIN_IN_SET(domset, d)) 10450Sstevel@tonic-gate continue; 10460Sstevel@tonic-gate mutex_enter(&wp->w_mutex); 10470Sstevel@tonic-gate wp->w_closed = 1; 10480Sstevel@tonic-gate cv_broadcast(&wp->w_cv); 10490Sstevel@tonic-gate mutex_exit(&wp->w_mutex); 10500Sstevel@tonic-gate } 10510Sstevel@tonic-gate } 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate /* 10540Sstevel@tonic-gate * Register the caller with the waiting list for the 10550Sstevel@tonic-gate * given domain. 10560Sstevel@tonic-gate * 10570Sstevel@tonic-gate * Protocol: 10580Sstevel@tonic-gate * 1st Local requester: register -> alloc -> 10590Sstevel@tonic-gate * put(wakeup|xdc) -> unregister 10600Sstevel@tonic-gate * Nth Local requester: register -> wait 10610Sstevel@tonic-gate * 1st Remote requester: register -> xdc -> wait 10620Sstevel@tonic-gate * Nth Remote requester: register -> wait 10630Sstevel@tonic-gate * 10640Sstevel@tonic-gate * Remote Responder: local alloc -> put(xdc) 10650Sstevel@tonic-gate * Local Handler: xdc -> put(wakeup) 10660Sstevel@tonic-gate * 10670Sstevel@tonic-gate * E.g. A standard slave allocation request: 10680Sstevel@tonic-gate * slave master 10690Sstevel@tonic-gate * ----- ------ 10700Sstevel@tonic-gate * idn_slab_alloc(remote) 10710Sstevel@tonic-gate * - register 10720Sstevel@tonic-gate * - xdc -> idn_handler 10730Sstevel@tonic-gate * - wait ... 10740Sstevel@tonic-gate * idn_slab_alloc(local) 10750Sstevel@tonic-gate * - register 10760Sstevel@tonic-gate * - alloc 10770Sstevel@tonic-gate * - put 10780Sstevel@tonic-gate * . wakeup [local] 10790Sstevel@tonic-gate * - unregister 10800Sstevel@tonic-gate * idn_handler <- - xdc 10810Sstevel@tonic-gate * - put DONE 10820Sstevel@tonic-gate * . wakeup [local] 10830Sstevel@tonic-gate * | 10840Sstevel@tonic-gate * V 10850Sstevel@tonic-gate * - wait 10860Sstevel@tonic-gate * . unregister 10870Sstevel@tonic-gate * DONE 10880Sstevel@tonic-gate */ 10890Sstevel@tonic-gate static int 10900Sstevel@tonic-gate smr_slabwaiter_register(int domid) 10910Sstevel@tonic-gate { 10920Sstevel@tonic-gate struct slabwaiter *wp; 10930Sstevel@tonic-gate int nwait; 10940Sstevel@tonic-gate procname_t proc = "smr_slabwaiter_register"; 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate 10970Sstevel@tonic-gate ASSERT(domid != IDN_NIL_DOMID); 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate ASSERT(DSLAB_READ_HELD(domid)); 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate wp = &idn.slabwaiter[domid]; 11020Sstevel@tonic-gate 11030Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&wp->w_mutex)); 11040Sstevel@tonic-gate 11050Sstevel@tonic-gate mutex_enter(&wp->w_mutex); 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate nwait = ++(wp->w_nwaiters); 11080Sstevel@tonic-gate ASSERT(nwait > 0); 11090Sstevel@tonic-gate 11100Sstevel@tonic-gate PR_SMR("%s: domain = %d, (new)nwaiters = %d\n", 11110Sstevel@tonic-gate proc, domid, nwait); 11120Sstevel@tonic-gate 11130Sstevel@tonic-gate if (nwait > 1) { 11140Sstevel@tonic-gate /* 11150Sstevel@tonic-gate * There are already waiters for slab allocations 11160Sstevel@tonic-gate * with respect to this domain. 11170Sstevel@tonic-gate */ 11180Sstevel@tonic-gate PR_SMR("%s: existing waiters for slabs for domain %d\n", 11190Sstevel@tonic-gate proc, domid); 11200Sstevel@tonic-gate mutex_exit(&wp->w_mutex); 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate return (nwait); 11230Sstevel@tonic-gate } 11240Sstevel@tonic-gate PR_SMR("%s: initial waiter for slabs for domain %d\n", proc, domid); 11250Sstevel@tonic-gate /* 11260Sstevel@tonic-gate * We are the first requester of a slab allocation for this 11270Sstevel@tonic-gate * respective domain. Need to prep waiting area for 11280Sstevel@tonic-gate * subsequent arrival of a slab. 11290Sstevel@tonic-gate */ 11300Sstevel@tonic-gate wp->w_sp = NULL; 11310Sstevel@tonic-gate wp->w_done = 0; 11320Sstevel@tonic-gate wp->w_serrno = 0; 11330Sstevel@tonic-gate 11340Sstevel@tonic-gate mutex_exit(&wp->w_mutex); 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate return (nwait); 11370Sstevel@tonic-gate } 11380Sstevel@tonic-gate 11390Sstevel@tonic-gate /* 11400Sstevel@tonic-gate * It is assumed that the caller had previously registered, 11410Sstevel@tonic-gate * but wakeup did not occur due to caller never waiting. 11420Sstevel@tonic-gate * Thus, slaballoc mutex is still held by caller. 11430Sstevel@tonic-gate * 11440Sstevel@tonic-gate * Returns: 0 11450Sstevel@tonic-gate * EINVAL 11460Sstevel@tonic-gate * EBUSY 11470Sstevel@tonic-gate * w_serrno (smr_slaballoc_put) 11480Sstevel@tonic-gate * (0, ENOLCK, ENOMEM, EDQUOT, EBUSY, ECANCELED) 11490Sstevel@tonic-gate */ 11500Sstevel@tonic-gate static int 11510Sstevel@tonic-gate smr_slabwaiter_unregister(int domid, smr_slab_t **spp) 11520Sstevel@tonic-gate { 11530Sstevel@tonic-gate struct slabwaiter *wp; 11540Sstevel@tonic-gate int serrno = 0; 11550Sstevel@tonic-gate procname_t proc = "smr_slabwaiter_unregister"; 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate 11580Sstevel@tonic-gate ASSERT(domid != IDN_NIL_DOMID); 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate wp = &idn.slabwaiter[domid]; 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate mutex_enter(&wp->w_mutex); 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate PR_SMR("%s: domain = %d, nwaiters = %d\n", 11650Sstevel@tonic-gate proc, domid, wp->w_nwaiters); 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate if (wp->w_nwaiters <= 0) { 11680Sstevel@tonic-gate /* 11690Sstevel@tonic-gate * Hmmm...nobody is registered! 11700Sstevel@tonic-gate */ 11710Sstevel@tonic-gate PR_SMR("%s: NO WAITERS (domid = %d)\n", proc, domid); 11720Sstevel@tonic-gate mutex_exit(&wp->w_mutex); 11730Sstevel@tonic-gate return (EINVAL); 11740Sstevel@tonic-gate } 11750Sstevel@tonic-gate (wp->w_nwaiters)--; 11760Sstevel@tonic-gate /* 11770Sstevel@tonic-gate * Is our present under the tree? 11780Sstevel@tonic-gate */ 11790Sstevel@tonic-gate if (!wp->w_done) { 11800Sstevel@tonic-gate /* 11810Sstevel@tonic-gate * Bummer...no presents. Let the caller know 11820Sstevel@tonic-gate * via a null slab pointer. 11830Sstevel@tonic-gate * Note that we don't clean up immediately since 11840Sstevel@tonic-gate * message might still come in for other waiters. 11850Sstevel@tonic-gate * Thus, late sleepers may still get a chance. 11860Sstevel@tonic-gate */ 11870Sstevel@tonic-gate PR_SMR("%s: bummer no slab allocated for domain %d\n", 11880Sstevel@tonic-gate proc, domid); 11890Sstevel@tonic-gate ASSERT(wp->w_sp == NULL); 11900Sstevel@tonic-gate (*spp) = NULL; 11910Sstevel@tonic-gate serrno = wp->w_closed ? ECANCELED : EBUSY; 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate } else { 11940Sstevel@tonic-gate (*spp) = wp->w_sp; 11950Sstevel@tonic-gate serrno = wp->w_serrno; 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate #ifdef DEBUG 11980Sstevel@tonic-gate if (serrno == 0) { 11990Sstevel@tonic-gate register smr_slab_t *sp; 12000Sstevel@tonic-gate 12010Sstevel@tonic-gate ASSERT(wp->w_sp); 12020Sstevel@tonic-gate PR_SMR("%s: allocation succeeded (domain %d)\n", 12030Sstevel@tonic-gate proc, domid); 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate DSLAB_LOCK_SHARED(domid); 12060Sstevel@tonic-gate for (sp = idn_domain[domid].dslab; sp; sp = sp->sl_next) 12070Sstevel@tonic-gate if (sp == wp->w_sp) 12080Sstevel@tonic-gate break; 12090Sstevel@tonic-gate if (sp == NULL) 12100Sstevel@tonic-gate cmn_err(CE_WARN, 12110Sstevel@tonic-gate "%s:%d: slab ptr = NULL", 12120Sstevel@tonic-gate proc, domid); 12130Sstevel@tonic-gate DSLAB_UNLOCK(domid); 12140Sstevel@tonic-gate } else { 12150Sstevel@tonic-gate PR_SMR("%s: allocation failed (domain %d) " 12160Sstevel@tonic-gate "[serrno = %d]\n", proc, domid, serrno); 12170Sstevel@tonic-gate } 12180Sstevel@tonic-gate #endif /* DEBUG */ 12190Sstevel@tonic-gate } 12200Sstevel@tonic-gate if (wp->w_nwaiters == 0) { 12210Sstevel@tonic-gate /* 12220Sstevel@tonic-gate * Last one turns out the lights. 12230Sstevel@tonic-gate */ 12240Sstevel@tonic-gate PR_SMR("%s: domain %d last waiter, turning out lights\n", 12250Sstevel@tonic-gate proc, domid); 12260Sstevel@tonic-gate wp->w_sp = NULL; 12270Sstevel@tonic-gate wp->w_done = 0; 12280Sstevel@tonic-gate wp->w_serrno = 0; 12290Sstevel@tonic-gate } 12300Sstevel@tonic-gate mutex_exit(&wp->w_mutex); 12310Sstevel@tonic-gate 12320Sstevel@tonic-gate return (serrno); 12330Sstevel@tonic-gate } 12340Sstevel@tonic-gate 12350Sstevel@tonic-gate /* 12360Sstevel@tonic-gate * Called to abort any slaballoc requests on behalf of the 12370Sstevel@tonic-gate * given domain. 12380Sstevel@tonic-gate */ 12390Sstevel@tonic-gate int 12400Sstevel@tonic-gate smr_slabwaiter_abort(int domid, int serrno) 12410Sstevel@tonic-gate { 12420Sstevel@tonic-gate ASSERT(serrno != 0); 12430Sstevel@tonic-gate 12440Sstevel@tonic-gate return (smr_slaballoc_put(domid, NULL, 0, serrno)); 12450Sstevel@tonic-gate } 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate /* 12480Sstevel@tonic-gate * Put ourselves into a timedwait waiting for slab to be 12490Sstevel@tonic-gate * allocated. 12500Sstevel@tonic-gate * Returns with slaballoc mutex dropped. 12510Sstevel@tonic-gate * 12520Sstevel@tonic-gate * Returns: EINVAL 12530Sstevel@tonic-gate * ETIMEDOUT 12540Sstevel@tonic-gate * smr_slabwatier_unregister 12550Sstevel@tonic-gate * (0, EINVAL, EBUSY, ENOMEM) 12560Sstevel@tonic-gate */ 12570Sstevel@tonic-gate static int 12580Sstevel@tonic-gate smr_slaballoc_wait(int domid, smr_slab_t **spp) 12590Sstevel@tonic-gate { 12600Sstevel@tonic-gate struct slabwaiter *wp; 12610Sstevel@tonic-gate int serrno = 0, serrno_unreg; 12620Sstevel@tonic-gate procname_t proc = "smr_slaballoc_wait"; 12630Sstevel@tonic-gate 12640Sstevel@tonic-gate 12650Sstevel@tonic-gate wp = &idn.slabwaiter[domid]; 12660Sstevel@tonic-gate 12670Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&wp->w_mutex)); 12680Sstevel@tonic-gate 12690Sstevel@tonic-gate mutex_enter(&wp->w_mutex); 12700Sstevel@tonic-gate 1271*931Smathue PR_SMR("%s: domain = %d, nwaiters = %d, wsp = 0x%p\n", 1272*931Smathue proc, domid, wp->w_nwaiters, wp->w_sp); 12730Sstevel@tonic-gate 12740Sstevel@tonic-gate if (wp->w_nwaiters <= 0) { 12750Sstevel@tonic-gate /* 12760Sstevel@tonic-gate * Hmmm...no waiters registered. 12770Sstevel@tonic-gate */ 12780Sstevel@tonic-gate PR_SMR("%s: domain %d, no waiters!\n", 12790Sstevel@tonic-gate proc, domid); 12800Sstevel@tonic-gate mutex_exit(&wp->w_mutex); 12810Sstevel@tonic-gate return (EINVAL); 12820Sstevel@tonic-gate } 12830Sstevel@tonic-gate ASSERT(DSLAB_READ_HELD(domid)); 12840Sstevel@tonic-gate DSLAB_UNLOCK(domid); 12850Sstevel@tonic-gate 12860Sstevel@tonic-gate if (!wp->w_done && !wp->w_closed) { 12870Sstevel@tonic-gate int rv; 12880Sstevel@tonic-gate 12890Sstevel@tonic-gate /* 12900Sstevel@tonic-gate * Only wait if data hasn't arrived yet. 12910Sstevel@tonic-gate */ 12920Sstevel@tonic-gate PR_SMR("%s: domain %d, going to sleep...\n", 12930Sstevel@tonic-gate proc, domid); 12940Sstevel@tonic-gate 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate rv = cv_timedwait_sig(&wp->w_cv, &wp->w_mutex, 12970Sstevel@tonic-gate lbolt + IDN_SLABALLOC_WAITTIME); 12980Sstevel@tonic-gate if (rv == -1) 12990Sstevel@tonic-gate serrno = ETIMEDOUT; 13000Sstevel@tonic-gate 13010Sstevel@tonic-gate PR_SMR("%s: domain %d, awakened (reason = %s)\n", 13020Sstevel@tonic-gate proc, domid, (rv == -1) ? "TIMEOUT" : "SIGNALED"); 13030Sstevel@tonic-gate } 13040Sstevel@tonic-gate /* 13050Sstevel@tonic-gate * We've awakened or request already filled! 13060Sstevel@tonic-gate * Unregister ourselves. 13070Sstevel@tonic-gate */ 13080Sstevel@tonic-gate mutex_exit(&wp->w_mutex); 13090Sstevel@tonic-gate 13100Sstevel@tonic-gate /* 13110Sstevel@tonic-gate * Any gifts will be entered into spp. 13120Sstevel@tonic-gate */ 13130Sstevel@tonic-gate serrno_unreg = smr_slabwaiter_unregister(domid, spp); 13140Sstevel@tonic-gate 13150Sstevel@tonic-gate /* 13160Sstevel@tonic-gate * Leave with reader lock on dslab_lock. 13170Sstevel@tonic-gate */ 13180Sstevel@tonic-gate DSLAB_LOCK_SHARED(domid); 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate if ((serrno_unreg == EBUSY) && (serrno == ETIMEDOUT)) 13210Sstevel@tonic-gate return (serrno); 13220Sstevel@tonic-gate else 13230Sstevel@tonic-gate return (serrno_unreg); 13240Sstevel@tonic-gate } 13250Sstevel@tonic-gate 13260Sstevel@tonic-gate /* 13270Sstevel@tonic-gate * A SMR slab was allocated on behalf of the given domain. 13280Sstevel@tonic-gate * Wakeup anybody that may have been waiting for the allocation. 13290Sstevel@tonic-gate * Note that if the domain is a remote one, i.e. master is allocating 13300Sstevel@tonic-gate * on behalf of a slave, it's up to the caller to transmit the 13310Sstevel@tonic-gate * allocation response to that domain. 13320Sstevel@tonic-gate * The force flag indicates that we want to install the slab for 13330Sstevel@tonic-gate * the given user regardless of whether there are waiters or not. 13340Sstevel@tonic-gate * This is used primarily in situations where a slave may have timed 13350Sstevel@tonic-gate * out before the response actually arrived. In this situation we 13360Sstevel@tonic-gate * don't want to send slab back to the master after we went through 13370Sstevel@tonic-gate * the trouble of allocating one. Master is _not_ allowed to do this 13380Sstevel@tonic-gate * for remote domains. 13390Sstevel@tonic-gate * 13400Sstevel@tonic-gate * Returns: -1 Non-registered waiter or waiting area garbaged. 13410Sstevel@tonic-gate * 0 Successfully performed operation. 13420Sstevel@tonic-gate */ 13430Sstevel@tonic-gate int 13440Sstevel@tonic-gate smr_slaballoc_put(int domid, smr_slab_t *sp, int forceflag, int serrno) 13450Sstevel@tonic-gate { 13460Sstevel@tonic-gate idn_domain_t *dp; 13470Sstevel@tonic-gate struct slabwaiter *wp; 13480Sstevel@tonic-gate procname_t proc = "smr_slaballoc_put"; 13490Sstevel@tonic-gate 13500Sstevel@tonic-gate 13510Sstevel@tonic-gate dp = &idn_domain[domid]; 13520Sstevel@tonic-gate 13530Sstevel@tonic-gate ASSERT(!serrno ? DSLAB_WRITE_HELD(domid) : 1); 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate if (domid == IDN_NIL_DOMID) 13560Sstevel@tonic-gate return (-1); 13570Sstevel@tonic-gate 13580Sstevel@tonic-gate ASSERT(serrno ? (sp == NULL) : (sp != NULL)); 13590Sstevel@tonic-gate 13600Sstevel@tonic-gate wp = &idn.slabwaiter[domid]; 13610Sstevel@tonic-gate 13620Sstevel@tonic-gate mutex_enter(&wp->w_mutex); 13630Sstevel@tonic-gate 1364*931Smathue PR_SMR("%s: domain = %d, bufp = 0x%p, ebufp = 0x%p, " 1365*931Smathue "(f = %d, se = %d)\n", proc, domid, 1366*931Smathue (sp ? sp->sl_start : 0), 1367*931Smathue (sp ? sp->sl_end : 0), forceflag, serrno); 13680Sstevel@tonic-gate 13690Sstevel@tonic-gate if (wp->w_nwaiters <= 0) { 13700Sstevel@tonic-gate /* 13710Sstevel@tonic-gate * There are no waiters!! Must have timed out 13720Sstevel@tonic-gate * and left. Oh well... 13730Sstevel@tonic-gate */ 13740Sstevel@tonic-gate PR_SMR("%s: no slaballoc waiters found for domain %d\n", 13750Sstevel@tonic-gate proc, domid); 13760Sstevel@tonic-gate if (!forceflag || serrno || !sp) { 13770Sstevel@tonic-gate /* 13780Sstevel@tonic-gate * No waiters and caller doesn't want to force it. 13790Sstevel@tonic-gate */ 13800Sstevel@tonic-gate mutex_exit(&wp->w_mutex); 13810Sstevel@tonic-gate return (-1); 13820Sstevel@tonic-gate } 13830Sstevel@tonic-gate PR_SMR("%s: forcing slab onto domain %d\n", proc, domid); 13840Sstevel@tonic-gate ASSERT(domid == idn.localid); 13850Sstevel@tonic-gate ASSERT(wp->w_sp == NULL); 13860Sstevel@tonic-gate wp->w_done = 0; 13870Sstevel@tonic-gate /* 13880Sstevel@tonic-gate * Now we fall through and let it be added in the 13890Sstevel@tonic-gate * regular manor. 13900Sstevel@tonic-gate */ 13910Sstevel@tonic-gate } 13920Sstevel@tonic-gate if (wp->w_done) { 13930Sstevel@tonic-gate /* 13940Sstevel@tonic-gate * There's at least one waiter so there has 13950Sstevel@tonic-gate * to be a slab structure waiting for us. 13960Sstevel@tonic-gate * If everything is going smoothly, there should only 13970Sstevel@tonic-gate * be one guy coming through the path of inserting 13980Sstevel@tonic-gate * an error or good slab. However, if a disconnect was 13990Sstevel@tonic-gate * detected, you may get several guys coming through 14000Sstevel@tonic-gate * trying to let everybody know. 14010Sstevel@tonic-gate */ 14020Sstevel@tonic-gate ASSERT(wp->w_serrno ? 14030Sstevel@tonic-gate (wp->w_sp == NULL) : (wp->w_sp != NULL)); 14040Sstevel@tonic-gate 14050Sstevel@tonic-gate cv_broadcast(&wp->w_cv); 14060Sstevel@tonic-gate mutex_exit(&wp->w_mutex); 14070Sstevel@tonic-gate 14080Sstevel@tonic-gate return (-1); 14090Sstevel@tonic-gate } 14100Sstevel@tonic-gate if (serrno != 0) { 14110Sstevel@tonic-gate /* 14120Sstevel@tonic-gate * Bummer...allocation failed. This call is simply 14130Sstevel@tonic-gate * to wake up the sleepers and let them know. 14140Sstevel@tonic-gate */ 14150Sstevel@tonic-gate PR_SMR("%s: slaballoc failed for domain %d\n", 14160Sstevel@tonic-gate proc, domid); 14170Sstevel@tonic-gate wp->w_serrno = serrno; 14180Sstevel@tonic-gate wp->w_done = 1; 14190Sstevel@tonic-gate cv_broadcast(&wp->w_cv); 14200Sstevel@tonic-gate mutex_exit(&wp->w_mutex); 14210Sstevel@tonic-gate 14220Sstevel@tonic-gate return (0); 14230Sstevel@tonic-gate } 14240Sstevel@tonic-gate PR_SMR("%s: putting slab into struct (domid=%d, localid=%d)\n", 14250Sstevel@tonic-gate proc, domid, idn.localid); 14260Sstevel@tonic-gate /* 14270Sstevel@tonic-gate * Prep the slab structure. 14280Sstevel@tonic-gate */ 14290Sstevel@tonic-gate 14300Sstevel@tonic-gate if (domid == idn.localid) { 14310Sstevel@tonic-gate /* 14320Sstevel@tonic-gate * Allocation was indeed for me. 14330Sstevel@tonic-gate * Slab may or may not be locked when 14340Sstevel@tonic-gate * we reach. Normally they will be locked 14350Sstevel@tonic-gate * if we're being called on behalf of a 14360Sstevel@tonic-gate * free, and not locked if on behalf of 14370Sstevel@tonic-gate * a new allocation request. 14380Sstevel@tonic-gate */ 14390Sstevel@tonic-gate lock_clear(&sp->sl_lock); 14400Sstevel@tonic-gate smr_alloc_buflist(sp); 14410Sstevel@tonic-gate #ifdef DEBUG 14420Sstevel@tonic-gate } else { 14430Sstevel@tonic-gate uint_t rv; 14440Sstevel@tonic-gate /* 14450Sstevel@tonic-gate * Slab was not allocated on my behalf. Must be 14460Sstevel@tonic-gate * a master request on behalf of some other domain. 14470Sstevel@tonic-gate * Prep appropriately. Slab should have been locked 14480Sstevel@tonic-gate * by smr_slab_reserve. 14490Sstevel@tonic-gate */ 14500Sstevel@tonic-gate rv = lock_try(&sp->sl_lock); 14510Sstevel@tonic-gate ASSERT(!rv); 14520Sstevel@tonic-gate ASSERT(sp->sl_domid == (short)domid); 14530Sstevel@tonic-gate #endif /* DEBUG */ 14540Sstevel@tonic-gate } 14550Sstevel@tonic-gate 14560Sstevel@tonic-gate /* 14570Sstevel@tonic-gate * Slab is ready to go. Insert it into the domain's 14580Sstevel@tonic-gate * slab list so once we wake everybody up they'll find it. 14590Sstevel@tonic-gate * You better have write lock if you're putting treasures 14600Sstevel@tonic-gate * there. 14610Sstevel@tonic-gate */ 14620Sstevel@tonic-gate ASSERT(DSLAB_WRITE_HELD(domid)); 14630Sstevel@tonic-gate 14640Sstevel@tonic-gate sp->sl_next = dp->dslab; 14650Sstevel@tonic-gate dp->dslab = sp; 14660Sstevel@tonic-gate dp->dnslabs++; 14670Sstevel@tonic-gate 14680Sstevel@tonic-gate /* 14690Sstevel@tonic-gate * It's possible to fall through here without waiters. 14700Sstevel@tonic-gate * This is a case where forceflag was set. 14710Sstevel@tonic-gate */ 14720Sstevel@tonic-gate if (wp->w_nwaiters > 0) { 14730Sstevel@tonic-gate wp->w_sp = sp; 14740Sstevel@tonic-gate wp->w_serrno = serrno; 14750Sstevel@tonic-gate wp->w_done = 1; 14760Sstevel@tonic-gate cv_broadcast(&wp->w_cv); 14770Sstevel@tonic-gate } else { 14780Sstevel@tonic-gate ASSERT(forceflag); 14790Sstevel@tonic-gate wp->w_sp = NULL; 14800Sstevel@tonic-gate wp->w_serrno = 0; 14810Sstevel@tonic-gate wp->w_done = 0; 14820Sstevel@tonic-gate } 14830Sstevel@tonic-gate mutex_exit(&wp->w_mutex); 14840Sstevel@tonic-gate 14850Sstevel@tonic-gate return (0); 14860Sstevel@tonic-gate } 14870Sstevel@tonic-gate 14880Sstevel@tonic-gate /* 14890Sstevel@tonic-gate * Get the slab representing [bufp,ebufp] from the respective 14900Sstevel@tonic-gate * domain's pool if all the buffers are free. Remove them from 14910Sstevel@tonic-gate * the domain's list and return it. 14920Sstevel@tonic-gate * If bufp == NULL, then return however many free ones you 14930Sstevel@tonic-gate * can find. 14940Sstevel@tonic-gate * List of slabs are returned locked (sl_lock). 14950Sstevel@tonic-gate * XXX - Need minimum limit to make sure we don't free up _all_ 14960Sstevel@tonic-gate * of our slabs! However, during a shutdown we will need 14970Sstevel@tonic-gate * method to free them all up regardless of locking. 14980Sstevel@tonic-gate */ 14990Sstevel@tonic-gate smr_slab_t * 15000Sstevel@tonic-gate smr_slaballoc_get(int domid, caddr_t bufp, caddr_t ebufp) 15010Sstevel@tonic-gate { 15020Sstevel@tonic-gate idn_domain_t *dp; 15030Sstevel@tonic-gate smr_slab_t *retsp, *sp, **psp; 15040Sstevel@tonic-gate int foundit, islocal = 0; 15050Sstevel@tonic-gate int nslabs; 15060Sstevel@tonic-gate procname_t proc = "smr_slaballoc_get"; 15070Sstevel@tonic-gate 1508*931Smathue PR_SMR("%s: getting slab for domain %d [bufp=0x%p, ebufp=0x%p]\n", 1509*931Smathue proc, domid, bufp, ebufp); 15100Sstevel@tonic-gate 15110Sstevel@tonic-gate dp = &idn_domain[domid]; 15120Sstevel@tonic-gate 15130Sstevel@tonic-gate ASSERT(DSLAB_WRITE_HELD(domid)); 15140Sstevel@tonic-gate 15150Sstevel@tonic-gate if ((sp = dp->dslab) == NULL) { 15160Sstevel@tonic-gate PR_SMR("%s: oops, no slabs for domain %d\n", 15170Sstevel@tonic-gate proc, domid); 15180Sstevel@tonic-gate return (NULL); 15190Sstevel@tonic-gate } 15200Sstevel@tonic-gate /* 15210Sstevel@tonic-gate * If domid is myself then I'm trying to get a slab out 15220Sstevel@tonic-gate * of my local pool. Otherwise, I'm the master and 15230Sstevel@tonic-gate * I'm trying to get the slab representative from the 15240Sstevel@tonic-gate * global pool. 15250Sstevel@tonic-gate */ 15260Sstevel@tonic-gate if (domid == idn.localid) 15270Sstevel@tonic-gate islocal = 1; 15280Sstevel@tonic-gate 15290Sstevel@tonic-gate if (bufp != NULL) { 15300Sstevel@tonic-gate nslabs = -1; 15310Sstevel@tonic-gate } else { 15320Sstevel@tonic-gate nslabs = *(int *)ebufp; 15330Sstevel@tonic-gate if (nslabs == 0) { 15340Sstevel@tonic-gate PR_SMR("%s: requested nslabs (%d) <= 0\n", 15350Sstevel@tonic-gate proc, nslabs); 15360Sstevel@tonic-gate return (NULL); 15370Sstevel@tonic-gate } else if (nslabs < 0) { 15380Sstevel@tonic-gate /* 15390Sstevel@tonic-gate * Caller wants them all! 15400Sstevel@tonic-gate */ 15410Sstevel@tonic-gate nslabs = (int)dp->dnslabs; 15420Sstevel@tonic-gate } 15430Sstevel@tonic-gate } 15440Sstevel@tonic-gate 15450Sstevel@tonic-gate retsp = NULL; 15460Sstevel@tonic-gate foundit = 0; 15470Sstevel@tonic-gate for (psp = &dp->dslab; sp; sp = *psp) { 15480Sstevel@tonic-gate int isbusy; 15490Sstevel@tonic-gate 15500Sstevel@tonic-gate if (bufp && (sp->sl_start != bufp)) { 15510Sstevel@tonic-gate psp = &sp->sl_next; 15520Sstevel@tonic-gate continue; 15530Sstevel@tonic-gate } 15540Sstevel@tonic-gate 15550Sstevel@tonic-gate if (bufp && (ebufp > sp->sl_end)) { 1556*931Smathue PR_SMR("%s: bufp/ebufp (0x%p/0x%p) " 1557*931Smathue "expected (0x%p/0x%p)\n", proc, bufp, ebufp, 1558*931Smathue sp->sl_start, sp->sl_end); 15590Sstevel@tonic-gate ASSERT(0); 15600Sstevel@tonic-gate } 15610Sstevel@tonic-gate /* 15620Sstevel@tonic-gate * We found the desired slab. Make sure 15630Sstevel@tonic-gate * it's free. 15640Sstevel@tonic-gate */ 15650Sstevel@tonic-gate foundit++; 15660Sstevel@tonic-gate isbusy = 0; 15670Sstevel@tonic-gate if (islocal) { 15680Sstevel@tonic-gate int spl; 15690Sstevel@tonic-gate 15700Sstevel@tonic-gate /* 15710Sstevel@tonic-gate * Some of the buffers in the slab 15720Sstevel@tonic-gate * are still in use. Unlock the 15730Sstevel@tonic-gate * buffers we locked and bail out. 15740Sstevel@tonic-gate */ 15750Sstevel@tonic-gate spl = splhi(); 15760Sstevel@tonic-gate if (!lock_try(&sp->sl_lock)) { 15770Sstevel@tonic-gate isbusy = 1; 15780Sstevel@tonic-gate foundit--; 15790Sstevel@tonic-gate } else if (sp->sl_inuse) { 15800Sstevel@tonic-gate lock_clear(&sp->sl_lock); 15810Sstevel@tonic-gate isbusy = 1; 15820Sstevel@tonic-gate foundit--; 15830Sstevel@tonic-gate } 15840Sstevel@tonic-gate splx(spl); 15850Sstevel@tonic-gate } else { 15860Sstevel@tonic-gate /* 15870Sstevel@tonic-gate * If not local, then I'm the master getting 15880Sstevel@tonic-gate * a slab from one of the slaves. In this case, 15890Sstevel@tonic-gate * their slab structs will always be locked. 15900Sstevel@tonic-gate */ 15910Sstevel@tonic-gate ASSERT(!lock_try(&sp->sl_lock)); 15920Sstevel@tonic-gate } 15930Sstevel@tonic-gate if (!isbusy) { 15940Sstevel@tonic-gate /* 15950Sstevel@tonic-gate * Delete the entry from the list and slap 15960Sstevel@tonic-gate * it onto our return list. 15970Sstevel@tonic-gate */ 15980Sstevel@tonic-gate *psp = sp->sl_next; 15990Sstevel@tonic-gate sp->sl_next = retsp; 16000Sstevel@tonic-gate retsp = sp; 16010Sstevel@tonic-gate } else { 16020Sstevel@tonic-gate psp = &sp->sl_next; 16030Sstevel@tonic-gate } 16040Sstevel@tonic-gate /* 16050Sstevel@tonic-gate * If bufp == NULL (alternate interface) and we haven't 16060Sstevel@tonic-gate * found the desired number of slabs yet, keep looking. 16070Sstevel@tonic-gate */ 16080Sstevel@tonic-gate if (bufp || (foundit == nslabs)) 16090Sstevel@tonic-gate break; 16100Sstevel@tonic-gate } 16110Sstevel@tonic-gate dp->dnslabs -= (short)foundit; 16120Sstevel@tonic-gate 16130Sstevel@tonic-gate if (foundit) { 16140Sstevel@tonic-gate PR_SMR("%s: found %d free slabs (domid = %d)\n", 16150Sstevel@tonic-gate proc, foundit, domid); 16160Sstevel@tonic-gate } else { 16170Sstevel@tonic-gate PR_SMR("%s: no free slabs found (domid = %d)\n", 16180Sstevel@tonic-gate proc, domid); 16190Sstevel@tonic-gate } 16200Sstevel@tonic-gate 16210Sstevel@tonic-gate /* 16220Sstevel@tonic-gate * If this is the alternate interface, need to return 16230Sstevel@tonic-gate * the number of slabs found in the ebufp parameter. 16240Sstevel@tonic-gate */ 16250Sstevel@tonic-gate if (bufp == NULL) 16260Sstevel@tonic-gate *(int *)ebufp = foundit; 16270Sstevel@tonic-gate 16280Sstevel@tonic-gate return (retsp); 16290Sstevel@tonic-gate } 16300Sstevel@tonic-gate 16310Sstevel@tonic-gate /* 16320Sstevel@tonic-gate * Wrapper to hide alternate interface to smr_slaballoc_get() 16330Sstevel@tonic-gate */ 16340Sstevel@tonic-gate smr_slab_t * 16350Sstevel@tonic-gate smr_slaballoc_get_n(int domid, int *nslabs) 16360Sstevel@tonic-gate { 16370Sstevel@tonic-gate smr_slab_t *sp; 16380Sstevel@tonic-gate 16390Sstevel@tonic-gate ASSERT(DSLAB_WRITE_HELD(domid)); 16400Sstevel@tonic-gate 16410Sstevel@tonic-gate sp = smr_slaballoc_get(domid, NULL, (caddr_t)nslabs); 16420Sstevel@tonic-gate 16430Sstevel@tonic-gate return (sp); 16440Sstevel@tonic-gate } 16450Sstevel@tonic-gate 16460Sstevel@tonic-gate /* 16470Sstevel@tonic-gate * Only called by master. Initialize slab pool based on local SMR. 16480Sstevel@tonic-gate * Returns number of slabs initialized. 16490Sstevel@tonic-gate * reserved_size = Length of area at the front of the NWR portion 16500Sstevel@tonic-gate * of the SMR to reserve and not make available for 16510Sstevel@tonic-gate * slab allocations. Must be a IDN_SMR_BUFSIZE multiple. 16520Sstevel@tonic-gate * reserved_area = Pointer to reserved area, if any. 16530Sstevel@tonic-gate */ 16540Sstevel@tonic-gate int 16550Sstevel@tonic-gate smr_slabpool_init(size_t reserved_size, caddr_t *reserved_area) 16560Sstevel@tonic-gate { 16570Sstevel@tonic-gate size_t nwr_available; 16580Sstevel@tonic-gate int minperpool, ntotslabs, nxslabs, nslabs; 16590Sstevel@tonic-gate register int p, pp; 16600Sstevel@tonic-gate register caddr_t bufp; 16610Sstevel@tonic-gate register smr_slab_t *sp; 16620Sstevel@tonic-gate 16630Sstevel@tonic-gate ASSERT(IDN_GLOCK_IS_EXCL()); 16640Sstevel@tonic-gate ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID); 16650Sstevel@tonic-gate 16660Sstevel@tonic-gate *reserved_area = NULL; 16670Sstevel@tonic-gate 16680Sstevel@tonic-gate nwr_available = MB2B(IDN_NWR_SIZE) - reserved_size; 16690Sstevel@tonic-gate 16700Sstevel@tonic-gate if ((idn.localid != IDN_GET_MASTERID()) || 16710Sstevel@tonic-gate (nwr_available < IDN_SLAB_SIZE) || 16720Sstevel@tonic-gate (idn.slabpool != NULL) || 16730Sstevel@tonic-gate ((reserved_size != 0) && (reserved_size & (IDN_SMR_BUFSIZE-1)))) { 16740Sstevel@tonic-gate return (-1); 16750Sstevel@tonic-gate } 16760Sstevel@tonic-gate 16770Sstevel@tonic-gate idn.slabpool = GETSTRUCT(struct slabpool, 1); 16780Sstevel@tonic-gate idn.slabpool->ntotslabs = ntotslabs = nwr_available / IDN_SLAB_SIZE; 16790Sstevel@tonic-gate ASSERT(ntotslabs > 0); 16800Sstevel@tonic-gate minperpool = (ntotslabs < IDN_SLAB_MINPERPOOL) ? 16810Sstevel@tonic-gate 1 : IDN_SLAB_MINPERPOOL; 16820Sstevel@tonic-gate idn.slabpool->npools = (ntotslabs + (minperpool - 1)) / minperpool; 16830Sstevel@tonic-gate 16840Sstevel@tonic-gate if ((idn.slabpool->npools & 1) == 0) { 16850Sstevel@tonic-gate /* 16860Sstevel@tonic-gate * npools needs to be odd for hashing algorithm. 16870Sstevel@tonic-gate */ 16880Sstevel@tonic-gate idn.slabpool->npools++; 16890Sstevel@tonic-gate } 16900Sstevel@tonic-gate ASSERT(idn.slabpool->npools > 0); 16910Sstevel@tonic-gate minperpool = (ntotslabs < idn.slabpool->npools) ? 16920Sstevel@tonic-gate 1 : (ntotslabs / idn.slabpool->npools); 16930Sstevel@tonic-gate 16940Sstevel@tonic-gate /* 16950Sstevel@tonic-gate * Calculate the number of extra slabs that will need to 16960Sstevel@tonic-gate * be alloted to the pools. This number will be less than 16970Sstevel@tonic-gate * npools. Only one extra slab is allocated to each pool 16980Sstevel@tonic-gate * until we have assigned all the extra slabs. 16990Sstevel@tonic-gate */ 17000Sstevel@tonic-gate if (ntotslabs > (idn.slabpool->npools * minperpool)) 17010Sstevel@tonic-gate nxslabs = ntotslabs - (idn.slabpool->npools * minperpool); 17020Sstevel@tonic-gate else 17030Sstevel@tonic-gate nxslabs = 0; 17040Sstevel@tonic-gate ASSERT((nxslabs >= 0) && (nxslabs < idn.slabpool->npools)); 17050Sstevel@tonic-gate 17060Sstevel@tonic-gate idn.slabpool->pool = GETSTRUCT(struct smr_slabtbl, 17070Sstevel@tonic-gate idn.slabpool->npools); 17080Sstevel@tonic-gate sp = GETSTRUCT(smr_slab_t, idn.slabpool->ntotslabs); 17090Sstevel@tonic-gate 17100Sstevel@tonic-gate idn.slabpool->savep = sp; 17110Sstevel@tonic-gate bufp = idn.smr.vaddr + reserved_size; 17120Sstevel@tonic-gate 17130Sstevel@tonic-gate for (p = nslabs = 0; 17140Sstevel@tonic-gate (p < idn.slabpool->npools) && (ntotslabs > 0); 17150Sstevel@tonic-gate p++, ntotslabs -= nslabs) { 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate nslabs = (ntotslabs < minperpool) ? ntotslabs : minperpool; 17180Sstevel@tonic-gate if (nxslabs > 0) { 17190Sstevel@tonic-gate nslabs++; 17200Sstevel@tonic-gate nxslabs--; 17210Sstevel@tonic-gate } 17220Sstevel@tonic-gate idn.slabpool->pool[p].sarray = sp; 17230Sstevel@tonic-gate for (pp = 0; pp < nslabs; pp++) { 17240Sstevel@tonic-gate 17250Sstevel@tonic-gate sp->sl_next = NULL; 17260Sstevel@tonic-gate sp->sl_start = bufp; 17270Sstevel@tonic-gate sp->sl_end = bufp = sp->sl_start + IDN_SLAB_SIZE; 17280Sstevel@tonic-gate sp->sl_lock = 0; 17290Sstevel@tonic-gate sp->sl_domid = (short)IDN_NIL_DOMID; 17300Sstevel@tonic-gate 17310Sstevel@tonic-gate sp++; 17320Sstevel@tonic-gate } 17330Sstevel@tonic-gate idn.slabpool->pool[p].nfree = nslabs; 17340Sstevel@tonic-gate idn.slabpool->pool[p].nslabs = nslabs; 17350Sstevel@tonic-gate } 17360Sstevel@tonic-gate ASSERT((ntotslabs == 0) && (nxslabs == 0)); 17370Sstevel@tonic-gate /* 17380Sstevel@tonic-gate * We should be at the end of the SMR at this point. 17390Sstevel@tonic-gate */ 17400Sstevel@tonic-gate ASSERT(bufp == (idn.smr.vaddr 17410Sstevel@tonic-gate + reserved_size 17420Sstevel@tonic-gate + (idn.slabpool->ntotslabs * IDN_SLAB_SIZE))); 17430Sstevel@tonic-gate 17440Sstevel@tonic-gate if (reserved_size != 0) 17450Sstevel@tonic-gate *reserved_area = idn.smr.vaddr; 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate return (0); 17480Sstevel@tonic-gate } 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate void 17510Sstevel@tonic-gate smr_slabpool_deinit() 17520Sstevel@tonic-gate { 17530Sstevel@tonic-gate if (idn.slabpool == NULL) 17540Sstevel@tonic-gate return; 17550Sstevel@tonic-gate 17560Sstevel@tonic-gate FREESTRUCT(idn.slabpool->savep, smr_slab_t, idn.slabpool->ntotslabs); 17570Sstevel@tonic-gate FREESTRUCT(idn.slabpool->pool, struct smr_slabtbl, 17580Sstevel@tonic-gate idn.slabpool->npools); 17590Sstevel@tonic-gate FREESTRUCT(idn.slabpool, struct slabpool, 1); 17600Sstevel@tonic-gate 17610Sstevel@tonic-gate idn.slabpool = NULL; 17620Sstevel@tonic-gate } 17630Sstevel@tonic-gate 17640Sstevel@tonic-gate void 17650Sstevel@tonic-gate smr_alloc_buflist(smr_slab_t *sp) 17660Sstevel@tonic-gate { 17670Sstevel@tonic-gate int n, nbufs; 17680Sstevel@tonic-gate caddr_t sbufp; 17690Sstevel@tonic-gate smr_slabbuf_t *hp, *bp; 17700Sstevel@tonic-gate 17710Sstevel@tonic-gate if (sp->sl_head) 17720Sstevel@tonic-gate return; 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate nbufs = (sp->sl_end - sp->sl_start) / IDN_SMR_BUFSIZE; 17750Sstevel@tonic-gate ASSERT(nbufs > 0); 17760Sstevel@tonic-gate if (nbufs <= 0) { 17770Sstevel@tonic-gate sp->sl_head = sp->sl_free = sp->sl_inuse = NULL; 17780Sstevel@tonic-gate return; 17790Sstevel@tonic-gate } 17800Sstevel@tonic-gate 17810Sstevel@tonic-gate hp = GETSTRUCT(smr_slabbuf_t, nbufs); 17820Sstevel@tonic-gate 17830Sstevel@tonic-gate sbufp = sp->sl_start; 17840Sstevel@tonic-gate for (n = 0, bp = hp; n < nbufs; bp++, n++) { 17850Sstevel@tonic-gate bp->sb_bufp = sbufp; 17860Sstevel@tonic-gate bp->sb_domid = IDN_NIL_DOMID; 17870Sstevel@tonic-gate bp->sb_next = bp + 1; 17880Sstevel@tonic-gate sbufp += IDN_SMR_BUFSIZE; 17890Sstevel@tonic-gate } 17900Sstevel@tonic-gate (--bp)->sb_next = NULL; 17910Sstevel@tonic-gate 17920Sstevel@tonic-gate sp->sl_head = sp->sl_free = hp; 17930Sstevel@tonic-gate sp->sl_inuse = NULL; 17940Sstevel@tonic-gate } 17950Sstevel@tonic-gate 17960Sstevel@tonic-gate void 17970Sstevel@tonic-gate smr_free_buflist(smr_slab_t *sp) 17980Sstevel@tonic-gate { 17990Sstevel@tonic-gate int nbufs; 18000Sstevel@tonic-gate 18010Sstevel@tonic-gate if (sp->sl_head == NULL) 18020Sstevel@tonic-gate return; 18030Sstevel@tonic-gate 18040Sstevel@tonic-gate nbufs = (sp->sl_end - sp->sl_start) / IDN_SMR_BUFSIZE; 18050Sstevel@tonic-gate 18060Sstevel@tonic-gate FREESTRUCT(sp->sl_head, smr_slabbuf_t, nbufs); 18070Sstevel@tonic-gate 18080Sstevel@tonic-gate sp->sl_head = sp->sl_free = sp->sl_inuse = NULL; 18090Sstevel@tonic-gate } 18100Sstevel@tonic-gate 18110Sstevel@tonic-gate /* 18120Sstevel@tonic-gate * Returns: 0 Successfully located a slab. 18130Sstevel@tonic-gate * -1 Failure. 18140Sstevel@tonic-gate */ 18150Sstevel@tonic-gate static smr_slab_t * 18160Sstevel@tonic-gate smr_slab_reserve(int domid) 18170Sstevel@tonic-gate { 18180Sstevel@tonic-gate register int p, nextp, s, nexts; 18190Sstevel@tonic-gate register smr_slab_t *spa; 18200Sstevel@tonic-gate int startp, starts; 18210Sstevel@tonic-gate int foundone = 0; 18220Sstevel@tonic-gate int spl; 18230Sstevel@tonic-gate procname_t proc = "smr_slab_reserve"; 18240Sstevel@tonic-gate 18250Sstevel@tonic-gate p = startp = SMR_SLABPOOL_HASH(domid); 18260Sstevel@tonic-gate nextp = -1; 18270Sstevel@tonic-gate 18280Sstevel@tonic-gate spl = splhi(); 18290Sstevel@tonic-gate while ((nextp != startp) && !foundone) { 18300Sstevel@tonic-gate 18310Sstevel@tonic-gate s = starts = SMR_SLAB_HASH(p, domid); 18320Sstevel@tonic-gate nexts = -1; 18330Sstevel@tonic-gate spa = &(idn.slabpool->pool[p].sarray[0]); 18340Sstevel@tonic-gate 18350Sstevel@tonic-gate while ((nexts != starts) && !foundone) { 18360Sstevel@tonic-gate if (lock_try(&spa[s].sl_lock)) { 18370Sstevel@tonic-gate foundone = 1; 18380Sstevel@tonic-gate break; 18390Sstevel@tonic-gate } 18400Sstevel@tonic-gate nexts = SMR_SLAB_HASHSTEP(p, s); 18410Sstevel@tonic-gate s = nexts; 18420Sstevel@tonic-gate } 18430Sstevel@tonic-gate if (foundone) 18440Sstevel@tonic-gate break; 18450Sstevel@tonic-gate nextp = SMR_SLABPOOL_HASHSTEP(p); 18460Sstevel@tonic-gate p = nextp; 18470Sstevel@tonic-gate } 18480Sstevel@tonic-gate splx(spl); 18490Sstevel@tonic-gate 18500Sstevel@tonic-gate if (foundone) { 18510Sstevel@tonic-gate ASSERT((&spa[s] >= idn.slabpool->savep) && 18520Sstevel@tonic-gate (&spa[s] < (idn.slabpool->savep + 18530Sstevel@tonic-gate idn.slabpool->ntotslabs))); 18540Sstevel@tonic-gate 18550Sstevel@tonic-gate spa[s].sl_domid = (short)domid; 18560Sstevel@tonic-gate 18570Sstevel@tonic-gate ATOMIC_DEC(idn.slabpool->pool[p].nfree); 18580Sstevel@tonic-gate 18590Sstevel@tonic-gate if (domid == idn.localid) { 18600Sstevel@tonic-gate smr_slab_t *nsp; 18610Sstevel@tonic-gate /* 18620Sstevel@tonic-gate * Caller is actually reserving a slab for 18630Sstevel@tonic-gate * themself which means they'll need the full 18640Sstevel@tonic-gate * slab structure to represent all of the I/O 18650Sstevel@tonic-gate * buffers. The "spa" is just a representative 18660Sstevel@tonic-gate * and doesn't contain the space to manage the 18670Sstevel@tonic-gate * individual buffers. Need to alloc a full-size 18680Sstevel@tonic-gate * struct. 18690Sstevel@tonic-gate * Note that this results in the returning 18700Sstevel@tonic-gate * smr_slab_t structure being unlocked. 18710Sstevel@tonic-gate */ 18720Sstevel@tonic-gate ASSERT(idn.localid == IDN_GET_MASTERID()); 18730Sstevel@tonic-gate nsp = GETSTRUCT(smr_slab_t, 1); 18740Sstevel@tonic-gate nsp->sl_start = spa[s].sl_start; 18750Sstevel@tonic-gate nsp->sl_end = spa[s].sl_end; 18760Sstevel@tonic-gate smr_alloc_buflist(nsp); 18770Sstevel@tonic-gate spa = nsp; 18780Sstevel@tonic-gate PR_SMR("%s: allocated full slab struct for domain %d\n", 18790Sstevel@tonic-gate proc, domid); 18800Sstevel@tonic-gate } else { 18810Sstevel@tonic-gate /* 18820Sstevel@tonic-gate * Slab structure gets returned locked. 18830Sstevel@tonic-gate */ 18840Sstevel@tonic-gate spa += s; 18850Sstevel@tonic-gate } 18860Sstevel@tonic-gate 1887*931Smathue PR_SMR("%s: allocated slab 0x%p (start=0x%p, size=%lu) for " 1888*931Smathue "domain %d\n", proc, spa, spa->sl_start, 18890Sstevel@tonic-gate spa->sl_end - spa->sl_start, domid); 18900Sstevel@tonic-gate } else { 18910Sstevel@tonic-gate PR_SMR("%s: FAILED to allocate for domain %d\n", 18920Sstevel@tonic-gate proc, domid); 18930Sstevel@tonic-gate spa = NULL; 18940Sstevel@tonic-gate } 18950Sstevel@tonic-gate 18960Sstevel@tonic-gate return (spa); 18970Sstevel@tonic-gate } 18980Sstevel@tonic-gate 18990Sstevel@tonic-gate static void 19000Sstevel@tonic-gate smr_slab_unreserve(int domid, smr_slab_t *sp) 19010Sstevel@tonic-gate { 19020Sstevel@tonic-gate register int p, nextp, s, nexts; 19030Sstevel@tonic-gate register smr_slab_t *spa; 19040Sstevel@tonic-gate int foundit = 0; 19050Sstevel@tonic-gate int startp, starts; 19060Sstevel@tonic-gate caddr_t bufp; 19070Sstevel@tonic-gate procname_t proc = "smr_slab_unreserve"; 19080Sstevel@tonic-gate 19090Sstevel@tonic-gate bufp = sp->sl_start; 19100Sstevel@tonic-gate p = startp = SMR_SLABPOOL_HASH(domid); 19110Sstevel@tonic-gate nextp = -1; 19120Sstevel@tonic-gate 19130Sstevel@tonic-gate while ((nextp != startp) && !foundit) { 19140Sstevel@tonic-gate 19150Sstevel@tonic-gate s = starts = SMR_SLAB_HASH(p, domid); 19160Sstevel@tonic-gate nexts = -1; 19170Sstevel@tonic-gate spa = &(idn.slabpool->pool[p].sarray[0]); 19180Sstevel@tonic-gate 19190Sstevel@tonic-gate while ((nexts != starts) && !foundit) { 19200Sstevel@tonic-gate if (spa[s].sl_start == bufp) { 19210Sstevel@tonic-gate foundit = 1; 19220Sstevel@tonic-gate break; 19230Sstevel@tonic-gate } 19240Sstevel@tonic-gate nexts = SMR_SLAB_HASHSTEP(p, s); 19250Sstevel@tonic-gate s = nexts; 19260Sstevel@tonic-gate } 19270Sstevel@tonic-gate if (foundit) 19280Sstevel@tonic-gate break; 19290Sstevel@tonic-gate nextp = SMR_SLABPOOL_HASHSTEP(p); 19300Sstevel@tonic-gate p = nextp; 19310Sstevel@tonic-gate } 19320Sstevel@tonic-gate if (foundit) { 19330Sstevel@tonic-gate ASSERT((&spa[s] >= idn.slabpool->savep) && 19340Sstevel@tonic-gate (&spa[s] < (idn.slabpool->savep + 19350Sstevel@tonic-gate idn.slabpool->ntotslabs))); 19360Sstevel@tonic-gate ASSERT(!lock_try(&spa[s].sl_lock)); 19370Sstevel@tonic-gate ASSERT(spa[s].sl_domid == (short)domid); 19380Sstevel@tonic-gate 19390Sstevel@tonic-gate spa[s].sl_next = NULL; 19400Sstevel@tonic-gate spa[s].sl_domid = (short)IDN_NIL_DOMID; 19410Sstevel@tonic-gate lock_clear(&spa[s].sl_lock); 19420Sstevel@tonic-gate 19430Sstevel@tonic-gate ATOMIC_INC(idn.slabpool->pool[p].nfree); 19440Sstevel@tonic-gate 1945*931Smathue PR_SMR("%s: freed (bufp=0x%p) for domain %d\n", 1946*931Smathue proc, bufp, domid); 19470Sstevel@tonic-gate 19480Sstevel@tonic-gate if (domid == idn.localid) { 19490Sstevel@tonic-gate /* 19500Sstevel@tonic-gate * Caller is actually unreserving a slab of their 19510Sstevel@tonic-gate * own. Note that only the master calls this 19520Sstevel@tonic-gate * routine. Since the master's local slab 19530Sstevel@tonic-gate * structures do not get entered into the global 19540Sstevel@tonic-gate * "representative" pool, we need to free up the 19550Sstevel@tonic-gate * data structure that was passed in. 19560Sstevel@tonic-gate */ 19570Sstevel@tonic-gate ASSERT(idn.localid == IDN_GET_MASTERID()); 19580Sstevel@tonic-gate ASSERT(sp != &spa[s]); 19590Sstevel@tonic-gate 19600Sstevel@tonic-gate smr_free_buflist(sp); 19610Sstevel@tonic-gate FREESTRUCT(sp, smr_slab_t, 1); 19620Sstevel@tonic-gate } else { 19630Sstevel@tonic-gate ASSERT(sp == &spa[s]); 19640Sstevel@tonic-gate } 19650Sstevel@tonic-gate } else { 19660Sstevel@tonic-gate /* 19670Sstevel@tonic-gate * Couldn't find slab entry for given buf! 19680Sstevel@tonic-gate */ 1969*931Smathue PR_SMR("%s: FAILED to free (bufp=0x%p) for domain %d\n", 1970*931Smathue proc, bufp, domid); 19710Sstevel@tonic-gate } 19720Sstevel@tonic-gate } 19730Sstevel@tonic-gate 19740Sstevel@tonic-gate /* 19750Sstevel@tonic-gate * The Reap Protocol: 19760Sstevel@tonic-gate * master slave 19770Sstevel@tonic-gate * ------ ----- 19780Sstevel@tonic-gate * smr_slab_reap_global 19790Sstevel@tonic-gate * - idn_broadcast_cmd(SLABREAP) -> idn_recv_cmd(SLABREAP) 19800Sstevel@tonic-gate * . idn_local_cmd(SLABREAP) - idn_recv_slabreap_req 19810Sstevel@tonic-gate * - smr_slab_reap . smr_slab_reap 19820Sstevel@tonic-gate * . smr_slaballoc_get_n - smr_slaballoc_get_n 19830Sstevel@tonic-gate * . smr_slab_free - smr_slab_free 19840Sstevel@tonic-gate * - smr_slab_free_local . smr_slab_free_remote 19850Sstevel@tonic-gate * . smr_slab_unreserve 19860Sstevel@tonic-gate * <- - idn_send_cmd(SLABFREE) 19870Sstevel@tonic-gate * idn_recv_cmd(SLABFREE) 19880Sstevel@tonic-gate * - idn_recv_slabfree_req 19890Sstevel@tonic-gate * . smr_slaballoc_get 19900Sstevel@tonic-gate * . smr_slab_free 19910Sstevel@tonic-gate * - smr_slab_free_local 19920Sstevel@tonic-gate * . smr_slab_unreserve 19930Sstevel@tonic-gate * . idn_send_slabfree_resp -> idn_recv_cmd(SLABFREE | ack) 19940Sstevel@tonic-gate * - idn_recv_slabfree_resp 19950Sstevel@tonic-gate * 19960Sstevel@tonic-gate * idn_recv_cmd(SLABREAP | ack) <- . idn_send_slabreap_resp 19970Sstevel@tonic-gate * - idn_recv_slabreap_resp DONE 19980Sstevel@tonic-gate * DONE 19990Sstevel@tonic-gate * 20000Sstevel@tonic-gate * Check available slabs and if we're below the threshold, kick 20010Sstevel@tonic-gate * off reaping to all remote domains. There is no guarantee remote 20020Sstevel@tonic-gate * domains will be able to free up any. 20030Sstevel@tonic-gate */ 20040Sstevel@tonic-gate static void 20050Sstevel@tonic-gate smr_slab_reap_global() 20060Sstevel@tonic-gate { 20070Sstevel@tonic-gate register int p, npools; 20080Sstevel@tonic-gate register int total_free = 0; 20090Sstevel@tonic-gate register struct smr_slabtbl *tblp; 20100Sstevel@tonic-gate static clock_t reap_last = 0; 20110Sstevel@tonic-gate procname_t proc = "smr_slab_reap_global"; 20120Sstevel@tonic-gate 20130Sstevel@tonic-gate ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID); 20140Sstevel@tonic-gate 20150Sstevel@tonic-gate DSLAB_LOCK_SHARED(idn.localid); 20160Sstevel@tonic-gate if (idn_domain[idn.localid].dslab_state != DSLAB_STATE_LOCAL) { 20170Sstevel@tonic-gate PR_SMR("%s: only allowed by master (%d)\n", 20180Sstevel@tonic-gate proc, IDN_GET_MASTERID()); 20190Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid); 20200Sstevel@tonic-gate return; 20210Sstevel@tonic-gate } 20220Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid); 20230Sstevel@tonic-gate 20240Sstevel@tonic-gate if ((lbolt > 0) && (lbolt > reap_last) && 20250Sstevel@tonic-gate ((lbolt - reap_last) < IDN_REAP_INTERVAL)) 20260Sstevel@tonic-gate return; 20270Sstevel@tonic-gate 20280Sstevel@tonic-gate reap_last = lbolt; 20290Sstevel@tonic-gate 20300Sstevel@tonic-gate ASSERT(idn.slabpool); 20310Sstevel@tonic-gate 20320Sstevel@tonic-gate npools = idn.slabpool->npools; 20330Sstevel@tonic-gate tblp = idn.slabpool->pool; 20340Sstevel@tonic-gate 20350Sstevel@tonic-gate for (p = 0; p < npools; tblp++, p++) 20360Sstevel@tonic-gate total_free += tblp->nfree; 20370Sstevel@tonic-gate 20380Sstevel@tonic-gate if (total_free <= IDN_SLAB_THRESHOLD) { 20390Sstevel@tonic-gate int diff, reap_per_domain; 20400Sstevel@tonic-gate 20410Sstevel@tonic-gate PR_SMR("%s: kicking off reaping " 2042*931Smathue "(total_free = %d, min = %d)\n", 20430Sstevel@tonic-gate proc, total_free, IDN_SLAB_THRESHOLD); 20440Sstevel@tonic-gate 20450Sstevel@tonic-gate diff = IDN_SLAB_THRESHOLD - total_free; 20460Sstevel@tonic-gate reap_per_domain = (diff < idn.ndomains) 20470Sstevel@tonic-gate ? 1 : (diff / idn.ndomains); 20480Sstevel@tonic-gate 20490Sstevel@tonic-gate idn_broadcast_cmd(IDNCMD_SLABREAP, reap_per_domain, 0, 0); 20500Sstevel@tonic-gate } 20510Sstevel@tonic-gate } 20520Sstevel@tonic-gate 20530Sstevel@tonic-gate void 20540Sstevel@tonic-gate smr_slab_reap(int domid, int *nslabs) 20550Sstevel@tonic-gate { 20560Sstevel@tonic-gate register int d; 20570Sstevel@tonic-gate int nreclaimed; 20580Sstevel@tonic-gate smr_slab_t *sp; 20590Sstevel@tonic-gate domainset_t reapset; 20600Sstevel@tonic-gate procname_t proc = "smr_slab_reap"; 20610Sstevel@tonic-gate 20620Sstevel@tonic-gate /* 20630Sstevel@tonic-gate * Should only be called on behalf of local 20640Sstevel@tonic-gate * domain. 20650Sstevel@tonic-gate */ 20660Sstevel@tonic-gate if (domid != idn.localid) { 20670Sstevel@tonic-gate PR_SMR("%s: called by domain %d, should only be local (%d)\n", 20680Sstevel@tonic-gate proc, domid, idn.localid); 20690Sstevel@tonic-gate ASSERT(0); 20700Sstevel@tonic-gate return; 20710Sstevel@tonic-gate } 20720Sstevel@tonic-gate /* 20730Sstevel@tonic-gate * Try and reclaim some buffers so we can possibly 20740Sstevel@tonic-gate * free up some slabs. 20750Sstevel@tonic-gate */ 20760Sstevel@tonic-gate reapset = idn.domset.ds_connected; 20770Sstevel@tonic-gate 20780Sstevel@tonic-gate IDN_GKSTAT_GLOBAL_EVENT(gk_reaps, gk_reap_last); 20790Sstevel@tonic-gate 20800Sstevel@tonic-gate nreclaimed = 0; 20810Sstevel@tonic-gate for (d = 0; d < MAX_DOMAINS; d++) { 20820Sstevel@tonic-gate int nr; 20830Sstevel@tonic-gate idn_domain_t *dp; 20840Sstevel@tonic-gate 20850Sstevel@tonic-gate if (!DOMAIN_IN_SET(reapset, d)) 20860Sstevel@tonic-gate continue; 20870Sstevel@tonic-gate 20880Sstevel@tonic-gate IDN_DLOCK_SHARED(d); 20890Sstevel@tonic-gate 20900Sstevel@tonic-gate dp = &idn_domain[d]; 20910Sstevel@tonic-gate if ((d == idn.localid) || (dp->dcpu < 0)) { 20920Sstevel@tonic-gate IDN_DUNLOCK(d); 20930Sstevel@tonic-gate continue; 20940Sstevel@tonic-gate } 20950Sstevel@tonic-gate /* 20960Sstevel@tonic-gate * Clean up any dead I/O errors if possible. 20970Sstevel@tonic-gate */ 20980Sstevel@tonic-gate if (dp->dioerr > 0) { 20990Sstevel@tonic-gate idn_domain_t *ldp; 21000Sstevel@tonic-gate register int cnt; 21010Sstevel@tonic-gate register smr_slabbuf_t *bp; 21020Sstevel@tonic-gate /* 21030Sstevel@tonic-gate * We need to grab the writer lock to prevent 21040Sstevel@tonic-gate * anybody from allocating buffers while we 21050Sstevel@tonic-gate * traverse the slabs outstanding. 21060Sstevel@tonic-gate */ 21070Sstevel@tonic-gate cnt = 0; 21080Sstevel@tonic-gate ldp = &idn_domain[idn.localid]; 21090Sstevel@tonic-gate IDN_DLOCK_EXCL(idn.localid); 21100Sstevel@tonic-gate DSLAB_LOCK_EXCL(idn.localid); 21110Sstevel@tonic-gate for (sp = ldp->dslab; sp; sp = sp->sl_next) 21120Sstevel@tonic-gate for (bp = sp->sl_inuse; bp; bp = bp->sb_next) 21130Sstevel@tonic-gate if (bp->sb_domid == d) 21140Sstevel@tonic-gate cnt++; 21150Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid); 21160Sstevel@tonic-gate ASSERT((dp->dio + dp->dioerr) >= cnt); 21170Sstevel@tonic-gate dp->dio = cnt; 21180Sstevel@tonic-gate dp->dioerr = 0; 21190Sstevel@tonic-gate IDN_DUNLOCK(idn.localid); 21200Sstevel@tonic-gate } 21210Sstevel@tonic-gate if ((dp->dstate == IDNDS_CONNECTED) && 21220Sstevel@tonic-gate ((nr = idn_reclaim_mboxdata(d, 0, -1)) > 0)) 21230Sstevel@tonic-gate nreclaimed += nr; 21240Sstevel@tonic-gate 21250Sstevel@tonic-gate IDN_DUNLOCK(d); 21260Sstevel@tonic-gate } 21270Sstevel@tonic-gate 21280Sstevel@tonic-gate DSLAB_LOCK_EXCL(domid); 21290Sstevel@tonic-gate sp = smr_slaballoc_get_n(domid, nslabs); 21300Sstevel@tonic-gate if (sp) { 21310Sstevel@tonic-gate IDN_GKSTAT_ADD(gk_reap_count, (ulong_t)(*nslabs)); 21320Sstevel@tonic-gate smr_slab_free(domid, sp); 21330Sstevel@tonic-gate } 21340Sstevel@tonic-gate DSLAB_UNLOCK(domid); 21350Sstevel@tonic-gate } 21360Sstevel@tonic-gate 21370Sstevel@tonic-gate /* 21380Sstevel@tonic-gate * --------------------------------------------------------------------- 21390Sstevel@tonic-gate * Remap the (IDN) shared memory region to a new physical address. 21400Sstevel@tonic-gate * Caller is expected to have performed a ecache flush if needed. 21410Sstevel@tonic-gate * --------------------------------------------------------------------- 21420Sstevel@tonic-gate */ 21430Sstevel@tonic-gate void 21440Sstevel@tonic-gate smr_remap(struct as *as, register caddr_t vaddr, 21450Sstevel@tonic-gate register pfn_t new_pfn, uint_t mblen) 21460Sstevel@tonic-gate { 21470Sstevel@tonic-gate tte_t tte; 21480Sstevel@tonic-gate size_t blen; 21490Sstevel@tonic-gate pgcnt_t p, npgs; 21500Sstevel@tonic-gate procname_t proc = "smr_remap"; 21510Sstevel@tonic-gate 21520Sstevel@tonic-gate if (va_to_pfn(vaddr) == new_pfn) { 2153*931Smathue PR_REMAP("%s: vaddr (0x%p) already mapped to pfn (0x%lx)\n", 2154*931Smathue proc, vaddr, new_pfn); 21550Sstevel@tonic-gate return; 21560Sstevel@tonic-gate } 21570Sstevel@tonic-gate 21580Sstevel@tonic-gate blen = MB2B(mblen); 21590Sstevel@tonic-gate npgs = btopr(blen); 21600Sstevel@tonic-gate ASSERT(npgs != 0); 21610Sstevel@tonic-gate 2162*931Smathue PR_REMAP("%s: va = 0x%p, pfn = 0x%lx, npgs = %ld, mb = %d MB (%ld)\n", 2163*931Smathue proc, vaddr, new_pfn, npgs, mblen, blen); 21640Sstevel@tonic-gate 21650Sstevel@tonic-gate /* 21660Sstevel@tonic-gate * Unmap the SMR virtual address from it's current 21670Sstevel@tonic-gate * mapping. 21680Sstevel@tonic-gate */ 21690Sstevel@tonic-gate hat_unload(as->a_hat, vaddr, blen, HAT_UNLOAD_UNLOCK); 21700Sstevel@tonic-gate 21710Sstevel@tonic-gate if (new_pfn == PFN_INVALID) 21720Sstevel@tonic-gate return; 21730Sstevel@tonic-gate 21740Sstevel@tonic-gate /* 21750Sstevel@tonic-gate * Map the SMR to the new physical address space, 21760Sstevel@tonic-gate * presumably a remote pfn. Cannot use hat_devload 21770Sstevel@tonic-gate * because it will think pfn represents non-memory, 21780Sstevel@tonic-gate * i.e. space since it may beyond his physmax. 21790Sstevel@tonic-gate */ 21800Sstevel@tonic-gate for (p = 0; p < npgs; p++) { 21810Sstevel@tonic-gate sfmmu_memtte(&tte, new_pfn, 21820Sstevel@tonic-gate PROT_READ | PROT_WRITE | HAT_NOSYNC, 21830Sstevel@tonic-gate TTE8K); 21840Sstevel@tonic-gate sfmmu_tteload(as->a_hat, &tte, vaddr, NULL, HAT_LOAD_LOCK); 21850Sstevel@tonic-gate 21860Sstevel@tonic-gate vaddr += MMU_PAGESIZE; 21870Sstevel@tonic-gate new_pfn++; 21880Sstevel@tonic-gate } 21890Sstevel@tonic-gate 21900Sstevel@tonic-gate PR_REMAP("%s: remapped %ld pages (expected %ld)\n", 21910Sstevel@tonic-gate proc, npgs, btopr(MB2B(mblen))); 21920Sstevel@tonic-gate } 2193