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