17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5d3d50737SRafael Vanoni * Common Development and Distribution License (the "License").
6d3d50737SRafael Vanoni * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21*07d06da5SSurya Prakki
227c478bd9Sstevel@tonic-gate /*
23d3d50737SRafael Vanoni * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate *
267c478bd9Sstevel@tonic-gate * Inter-Domain Network
277c478bd9Sstevel@tonic-gate *
287c478bd9Sstevel@tonic-gate * Shared Memory Region (SMR) supporting code.
297c478bd9Sstevel@tonic-gate */
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <sys/machparam.h>
347c478bd9Sstevel@tonic-gate #include <sys/debug.h>
357c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
367c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
377c478bd9Sstevel@tonic-gate #include <sys/mutex.h>
387c478bd9Sstevel@tonic-gate #include <sys/rwlock.h>
397c478bd9Sstevel@tonic-gate #include <sys/systm.h>
407c478bd9Sstevel@tonic-gate #include <sys/machlock.h>
417c478bd9Sstevel@tonic-gate #include <sys/membar.h>
427c478bd9Sstevel@tonic-gate #include <sys/mman.h>
437c478bd9Sstevel@tonic-gate #include <vm/hat.h>
447c478bd9Sstevel@tonic-gate #include <vm/as.h>
457c478bd9Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
467c478bd9Sstevel@tonic-gate #include <sys/vm_machparam.h>
477c478bd9Sstevel@tonic-gate #include <sys/x_call.h>
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate #include <sys/idn.h>
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate #ifdef DEBUG
527c478bd9Sstevel@tonic-gate #define DIOCHECK(domid) \
537c478bd9Sstevel@tonic-gate { \
547c478bd9Sstevel@tonic-gate int _dio; \
557c478bd9Sstevel@tonic-gate if ((_dio = idn_domain[domid].dio) < 0) { \
567c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, \
577c478bd9Sstevel@tonic-gate ">>>>> file %s, line %d: domain %d, dio = %d", \
587c478bd9Sstevel@tonic-gate __FILE__, __LINE__, (domid), _dio); \
597c478bd9Sstevel@tonic-gate } \
607c478bd9Sstevel@tonic-gate }
617c478bd9Sstevel@tonic-gate #else
627c478bd9Sstevel@tonic-gate #define DIOCHECK(domid)
637c478bd9Sstevel@tonic-gate #endif /* DEBUG */
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate static int smr_slab_alloc_local(int domid, smr_slab_t **spp);
667c478bd9Sstevel@tonic-gate static int smr_slab_alloc_remote(int domid, smr_slab_t **spp);
677c478bd9Sstevel@tonic-gate static void smr_slab_free_local(int domid, smr_slab_t *sp);
687c478bd9Sstevel@tonic-gate static void smr_slab_free_remote(int domid, smr_slab_t *sp);
697c478bd9Sstevel@tonic-gate static int smr_slabwaiter_register(int domid);
707c478bd9Sstevel@tonic-gate static int smr_slabwaiter_unregister(int domid, smr_slab_t **spp);
717c478bd9Sstevel@tonic-gate static int smr_slaballoc_wait(int domid, smr_slab_t **spp);
727c478bd9Sstevel@tonic-gate static smr_slab_t *smr_slab_reserve(int domid);
737c478bd9Sstevel@tonic-gate static void smr_slab_unreserve(int domid, smr_slab_t *sp);
747c478bd9Sstevel@tonic-gate static void smr_slab_reap_global();
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate * Can only be called by the master. Allocate a slab from the
787c478bd9Sstevel@tonic-gate * local pool representing the SMR, on behalf of the given
797c478bd9Sstevel@tonic-gate * domain. Slab is either being requested for use by the
807c478bd9Sstevel@tonic-gate * local domain (i.e. domid == idn.localid), or it's being
817c478bd9Sstevel@tonic-gate * allocated to give to a remote domain which requested one.
827c478bd9Sstevel@tonic-gate * In the base of allocating on behalf of a remote domain,
837c478bd9Sstevel@tonic-gate * smr_slab_t structure is used simply to manage ownership.
847c478bd9Sstevel@tonic-gate *
857c478bd9Sstevel@tonic-gate * Returns: smr_slaballoc_wait
867c478bd9Sstevel@tonic-gate * (EINVAL, ETIMEDOUT)
877c478bd9Sstevel@tonic-gate * smr_slabwatier_unregister
887c478bd9Sstevel@tonic-gate * (0, EINVAL, EBUSY, ENOMEM)
897c478bd9Sstevel@tonic-gate * ENOLCK
907c478bd9Sstevel@tonic-gate */
917c478bd9Sstevel@tonic-gate static int
smr_slab_alloc_local(int domid,smr_slab_t ** spp)927c478bd9Sstevel@tonic-gate smr_slab_alloc_local(int domid, smr_slab_t **spp)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate int serrno = 0;
957c478bd9Sstevel@tonic-gate int nwait;
967c478bd9Sstevel@tonic-gate smr_slab_t *sp;
977c478bd9Sstevel@tonic-gate idn_domain_t *dp;
987c478bd9Sstevel@tonic-gate
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate /*
1017c478bd9Sstevel@tonic-gate * Only the master can make local allocations.
1027c478bd9Sstevel@tonic-gate */
1037c478bd9Sstevel@tonic-gate ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
1047c478bd9Sstevel@tonic-gate ASSERT(idn.localid == IDN_GET_MASTERID());
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate *spp = NULL;
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate dp = &idn_domain[domid];
1097c478bd9Sstevel@tonic-gate ASSERT(DSLAB_READ_HELD(domid));
1107c478bd9Sstevel@tonic-gate ASSERT(dp->dslab_state == DSLAB_STATE_LOCAL);
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate * Register myself with the waiting list.
1147c478bd9Sstevel@tonic-gate */
1157c478bd9Sstevel@tonic-gate nwait = smr_slabwaiter_register(domid);
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate if (nwait > 1) {
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate * XXX - old comment?
1207c478bd9Sstevel@tonic-gate * Need to drop the read lock _after_ registering
1217c478bd9Sstevel@tonic-gate * ourselves with the potential wait list for this allocation.
1227c478bd9Sstevel@tonic-gate * Although this allocation is not a remote one, we could
1237c478bd9Sstevel@tonic-gate * still have multiple threads on the master trying to
1247c478bd9Sstevel@tonic-gate * satisfy (allocate) request on behalf of a remote domain.
1257c478bd9Sstevel@tonic-gate */
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate * Somebody is already in the process of satisfying
1287c478bd9Sstevel@tonic-gate * the allocation request for this respective
1297c478bd9Sstevel@tonic-gate * domain. All we need to do is wait and let
1307c478bd9Sstevel@tonic-gate * it happen.
1317c478bd9Sstevel@tonic-gate */
1327c478bd9Sstevel@tonic-gate serrno = smr_slaballoc_wait(domid, spp);
1337c478bd9Sstevel@tonic-gate return (serrno);
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate /*
1367c478bd9Sstevel@tonic-gate * I'm the original slab requester for this domain. It's local
1377c478bd9Sstevel@tonic-gate * so go ahead and do the job.
1387c478bd9Sstevel@tonic-gate */
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate if ((sp = smr_slab_reserve(domid)) == NULL)
1417c478bd9Sstevel@tonic-gate serrno = ENOMEM;
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate /*
1447c478bd9Sstevel@tonic-gate * Allocation may have failed. In either case we've
1457c478bd9Sstevel@tonic-gate * got to do the put to at least wake potential waiters up.
1467c478bd9Sstevel@tonic-gate */
1477c478bd9Sstevel@tonic-gate if (!serrno) {
1487c478bd9Sstevel@tonic-gate if (DSLAB_LOCK_TRYUPGRADE(domid) == 0) {
1497c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(domid);
1507c478bd9Sstevel@tonic-gate DSLAB_LOCK_EXCL(domid);
1517c478bd9Sstevel@tonic-gate }
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate (void) smr_slaballoc_put(domid, sp, 0, serrno);
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate * If serrno is ENOLCK here, then we must have failed
1587c478bd9Sstevel@tonic-gate * on the upgrade above, so lock already dropped.
1597c478bd9Sstevel@tonic-gate */
1607c478bd9Sstevel@tonic-gate if (serrno != ENOLCK) {
1617c478bd9Sstevel@tonic-gate /*
1627c478bd9Sstevel@tonic-gate * Need to drop since reaping may be recursive?
1637c478bd9Sstevel@tonic-gate */
1647c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(domid);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate * Since we were the original requester but never went
1697c478bd9Sstevel@tonic-gate * to sleep, we need to directly unregister ourselves
1707c478bd9Sstevel@tonic-gate * from the waiting list.
1717c478bd9Sstevel@tonic-gate */
1727c478bd9Sstevel@tonic-gate serrno = smr_slabwaiter_unregister(domid, spp);
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate * Now that we've satisfied the request, let's check if any
1767c478bd9Sstevel@tonic-gate * reaping is necessary. Only the master does this and only
1777c478bd9Sstevel@tonic-gate * when allocating slabs, an infrequent event :-o
1787c478bd9Sstevel@tonic-gate */
1797c478bd9Sstevel@tonic-gate smr_slab_reap_global();
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate ASSERT((serrno == 0) ? (*spp != NULL) : (*spp == NULL));
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate DSLAB_LOCK_SHARED(domid);
1847c478bd9Sstevel@tonic-gate
1857c478bd9Sstevel@tonic-gate return (serrno);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate * Can only be called by a slave on behalf of himself. Need to
1907c478bd9Sstevel@tonic-gate * make a request to the master to allocate a slab of SMR buffers
1917c478bd9Sstevel@tonic-gate * for the local domain.
1927c478bd9Sstevel@tonic-gate *
1937c478bd9Sstevel@tonic-gate * Returns: smr_slaballoc_wait
1947c478bd9Sstevel@tonic-gate * (0, EINVAL, EBUSY, ENOMEM)
1957c478bd9Sstevel@tonic-gate * ENOLCK
1967c478bd9Sstevel@tonic-gate * ECANCELED
1977c478bd9Sstevel@tonic-gate */
1987c478bd9Sstevel@tonic-gate static int
smr_slab_alloc_remote(int domid,smr_slab_t ** spp)1997c478bd9Sstevel@tonic-gate smr_slab_alloc_remote(int domid, smr_slab_t **spp)
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate int nwait;
2027c478bd9Sstevel@tonic-gate int serrno = 0;
2037c478bd9Sstevel@tonic-gate int bailout = 0;
2047c478bd9Sstevel@tonic-gate int masterid;
2057c478bd9Sstevel@tonic-gate idn_domain_t *dp, *mdp = NULL;
2067c478bd9Sstevel@tonic-gate procname_t proc = "smr_slab_alloc_remote";
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate /*
2097c478bd9Sstevel@tonic-gate * Only slaves make remote allocations.
2107c478bd9Sstevel@tonic-gate */
2117c478bd9Sstevel@tonic-gate ASSERT(idn.localid != IDN_GET_MASTERID());
2127c478bd9Sstevel@tonic-gate ASSERT(domid == idn.localid);
2137c478bd9Sstevel@tonic-gate ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate *spp = NULL;
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate dp = &idn_domain[domid];
2187c478bd9Sstevel@tonic-gate ASSERT(DSLAB_READ_HELD(domid));
2197c478bd9Sstevel@tonic-gate ASSERT(dp->dslab_state == DSLAB_STATE_REMOTE);
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate /*
2227c478bd9Sstevel@tonic-gate * Register myself with the slaballoc waiting list.
2237c478bd9Sstevel@tonic-gate * Note that only allow one outstanding allocation
2247c478bd9Sstevel@tonic-gate * request for the given domain. Other callers which
2257c478bd9Sstevel@tonic-gate * detect a slab is needed simply get stuck on the
2267c478bd9Sstevel@tonic-gate * waiting list waiting for the original caller to
2277c478bd9Sstevel@tonic-gate * get the job done.
2287c478bd9Sstevel@tonic-gate * The waiter_register routine will allocate the necessary
2297c478bd9Sstevel@tonic-gate * slab structure which will ultimately be inserted in
2307c478bd9Sstevel@tonic-gate * the domain's slab list via smr_slaballoc_put().
2317c478bd9Sstevel@tonic-gate */
2327c478bd9Sstevel@tonic-gate nwait = smr_slabwaiter_register(domid);
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate /*
2357c478bd9Sstevel@tonic-gate * Make sure we have a connection with the master
2367c478bd9Sstevel@tonic-gate * before we wait around for nothing and send a
2377c478bd9Sstevel@tonic-gate * command off to nowhere.
2387c478bd9Sstevel@tonic-gate * First do a quick (no lock) check for global okayness.
2397c478bd9Sstevel@tonic-gate */
2407c478bd9Sstevel@tonic-gate if ((idn.state != IDNGS_ONLINE) ||
2417c478bd9Sstevel@tonic-gate ((masterid = IDN_GET_MASTERID()) == IDN_NIL_DOMID)) {
2427c478bd9Sstevel@tonic-gate bailout = 1;
2437c478bd9Sstevel@tonic-gate serrno = ECANCELED;
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate /*
2467c478bd9Sstevel@tonic-gate * We need to drop our read lock _before_ acquiring the
2477c478bd9Sstevel@tonic-gate * slaballoc waiter lock. This is necessary because the
2487c478bd9Sstevel@tonic-gate * thread that receives the slab alloc response and fills
2497c478bd9Sstevel@tonic-gate * in the slab structure will need to grab the domain write
2507c478bd9Sstevel@tonic-gate * lock while holding onto the slaballoc waiter lock.
2517c478bd9Sstevel@tonic-gate * Potentially could deadlock if we didn't drop our domain
2527c478bd9Sstevel@tonic-gate * lock before. Plus, we've registered.
2537c478bd9Sstevel@tonic-gate *
2547c478bd9Sstevel@tonic-gate * 4093209 - Note also that we do this _after_ the check for
2557c478bd9Sstevel@tonic-gate * idn.masterid where we grab the READER global
2567c478bd9Sstevel@tonic-gate * lock. This is to prevent somebody from
2577c478bd9Sstevel@tonic-gate * changing our state after we drop the drwlock.
2587c478bd9Sstevel@tonic-gate * A deadlock can occur when shutting down a
2597c478bd9Sstevel@tonic-gate * domain we're holding the
2607c478bd9Sstevel@tonic-gate */
2617c478bd9Sstevel@tonic-gate
2627c478bd9Sstevel@tonic-gate if (!bailout) {
2637c478bd9Sstevel@tonic-gate mdp = &idn_domain[masterid];
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate * Global state is okay. Let's double check the
2667c478bd9Sstevel@tonic-gate * state of our actual target domain.
2677c478bd9Sstevel@tonic-gate */
2687c478bd9Sstevel@tonic-gate if (mdp->dstate != IDNDS_CONNECTED) {
2697c478bd9Sstevel@tonic-gate bailout = 1;
2707c478bd9Sstevel@tonic-gate serrno = ECANCELED;
2717c478bd9Sstevel@tonic-gate } else if (IDN_DLOCK_TRY_SHARED(masterid)) {
2727c478bd9Sstevel@tonic-gate if (mdp->dstate != IDNDS_CONNECTED) {
2737c478bd9Sstevel@tonic-gate bailout = 1;
2747c478bd9Sstevel@tonic-gate serrno = ECANCELED;
2757c478bd9Sstevel@tonic-gate IDN_DUNLOCK(masterid);
2767c478bd9Sstevel@tonic-gate } else if (nwait != 1) {
2777c478bd9Sstevel@tonic-gate IDN_DUNLOCK(masterid);
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate * Note that keep the drwlock(read) for
2817c478bd9Sstevel@tonic-gate * the target (master) domain if it appears
2827c478bd9Sstevel@tonic-gate * we're the lucky one to send the command.
2837c478bd9Sstevel@tonic-gate * We hold onto the lock until we've actually
2847c478bd9Sstevel@tonic-gate * sent the command out.
2857c478bd9Sstevel@tonic-gate * We don't reach this place unless it
2867c478bd9Sstevel@tonic-gate * appears everything is kosher with
2877c478bd9Sstevel@tonic-gate * the target (master) domain.
2887c478bd9Sstevel@tonic-gate */
2897c478bd9Sstevel@tonic-gate } else {
2907c478bd9Sstevel@tonic-gate bailout = 1;
2917c478bd9Sstevel@tonic-gate serrno = ENOLCK;
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate
2957c478bd9Sstevel@tonic-gate if (bailout) {
2967c478bd9Sstevel@tonic-gate ASSERT(serrno);
2977c478bd9Sstevel@tonic-gate /*
2987c478bd9Sstevel@tonic-gate * Gotta bail. Abort operation. Error result
2997c478bd9Sstevel@tonic-gate * will be picked up when we attempt to wait.
3007c478bd9Sstevel@tonic-gate */
3017c478bd9Sstevel@tonic-gate PR_SMR("%s: BAILING OUT on behalf domain %d "
3027c478bd9Sstevel@tonic-gate "(err=%d, gs=%s, ms=%s)\n",
3037c478bd9Sstevel@tonic-gate proc, domid, serrno, idngs_str[idn.state],
3047c478bd9Sstevel@tonic-gate (masterid == IDN_NIL_DOMID)
3057c478bd9Sstevel@tonic-gate ? "unknown" : idnds_str[idn_domain[masterid].dstate]);
3067c478bd9Sstevel@tonic-gate (void) smr_slabwaiter_abort(domid, serrno);
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate } else if (nwait == 1) {
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate * We are the original requester. Initiate the
3117c478bd9Sstevel@tonic-gate * actual request to the master.
3127c478bd9Sstevel@tonic-gate */
313d3d50737SRafael Vanoni idn_send_cmd(masterid, IDNCMD_SLABALLOC, IDN_SLAB_SIZE, 0, 0);
3147c478bd9Sstevel@tonic-gate ASSERT(mdp);
3157c478bd9Sstevel@tonic-gate IDN_DUNLOCK(masterid);
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate /*
3197c478bd9Sstevel@tonic-gate * Wait here for response. Once awakened func returns
3207c478bd9Sstevel@tonic-gate * with slab structure possibly filled with gifts!
3217c478bd9Sstevel@tonic-gate */
3227c478bd9Sstevel@tonic-gate serrno = smr_slaballoc_wait(domid, spp);
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate return (serrno);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate /*
3287c478bd9Sstevel@tonic-gate * Allocate a slab from the Master on behalf
3297c478bd9Sstevel@tonic-gate * of the given domain. Note that master uses
3307c478bd9Sstevel@tonic-gate * this function to allocate slabs on behalf of
3317c478bd9Sstevel@tonic-gate * remote domains also.
3327c478bd9Sstevel@tonic-gate * Entered with drwlock held.
3337c478bd9Sstevel@tonic-gate * Leaves with drwlock dropped.
3347c478bd9Sstevel@tonic-gate * Returns: EDQUOT
3357c478bd9Sstevel@tonic-gate * EINVAL
3367c478bd9Sstevel@tonic-gate * ENOLCK
3377c478bd9Sstevel@tonic-gate * smr_slab_alloc_local
3387c478bd9Sstevel@tonic-gate * smr_slab_alloc_remote
3397c478bd9Sstevel@tonic-gate * (0, EINVAL, EBUSY, ENOMEM)
3407c478bd9Sstevel@tonic-gate */
3417c478bd9Sstevel@tonic-gate int
smr_slab_alloc(int domid,smr_slab_t ** spp)3427c478bd9Sstevel@tonic-gate smr_slab_alloc(int domid, smr_slab_t **spp)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate int serrno = 0;
3457c478bd9Sstevel@tonic-gate idn_domain_t *dp;
3467c478bd9Sstevel@tonic-gate procname_t proc = "smr_slab_alloc";
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate dp = &idn_domain[domid];
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate ASSERT(DSLAB_READ_HELD(domid));
3527c478bd9Sstevel@tonic-gate ASSERT(dp->dslab_state != DSLAB_STATE_UNKNOWN);
3537c478bd9Sstevel@tonic-gate
3547c478bd9Sstevel@tonic-gate *spp = NULL;
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate switch (dp->dslab_state) {
3577c478bd9Sstevel@tonic-gate case DSLAB_STATE_UNKNOWN:
3587c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
3597c478bd9Sstevel@tonic-gate "IDN: 300: no slab allocations without a master");
3607c478bd9Sstevel@tonic-gate serrno = EINVAL;
3617c478bd9Sstevel@tonic-gate break;
3627c478bd9Sstevel@tonic-gate
3637c478bd9Sstevel@tonic-gate case DSLAB_STATE_LOCAL:
3647c478bd9Sstevel@tonic-gate /*
3657c478bd9Sstevel@tonic-gate * If I'm the master, then get a slab
3667c478bd9Sstevel@tonic-gate * from the local SMR pool, but only
3677c478bd9Sstevel@tonic-gate * if the number of allocated slabs has
3687c478bd9Sstevel@tonic-gate * not been exceeded.
3697c478bd9Sstevel@tonic-gate */
3707c478bd9Sstevel@tonic-gate if (((int)dp->dnslabs < IDN_SLAB_MAXPERDOMAIN) ||
3717c478bd9Sstevel@tonic-gate !IDN_SLAB_MAXPERDOMAIN)
3727c478bd9Sstevel@tonic-gate serrno = smr_slab_alloc_local(domid, spp);
3737c478bd9Sstevel@tonic-gate else
3747c478bd9Sstevel@tonic-gate serrno = EDQUOT;
3757c478bd9Sstevel@tonic-gate break;
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate case DSLAB_STATE_REMOTE:
3787c478bd9Sstevel@tonic-gate /*
3797c478bd9Sstevel@tonic-gate * Have to make a remote request.
3807c478bd9Sstevel@tonic-gate * In order to prevent overwhelming the master
3817c478bd9Sstevel@tonic-gate * with a bunch of requests that he won't be able
3827c478bd9Sstevel@tonic-gate * to handle we do a check to see if we're still
3837c478bd9Sstevel@tonic-gate * under quota. Note that the limit is known
3847c478bd9Sstevel@tonic-gate * apriori based on the SMR/NWR size and
3857c478bd9Sstevel@tonic-gate * IDN_SLAB_MINTOTAL. Domains must have the same
3867c478bd9Sstevel@tonic-gate * size SMR/NWR, however they can have different
3877c478bd9Sstevel@tonic-gate * IDN_SLAB_MINTOTAL. Thus a domain could throttle
3887c478bd9Sstevel@tonic-gate * itself however it wishes.
3897c478bd9Sstevel@tonic-gate */
3907c478bd9Sstevel@tonic-gate if (((int)dp->dnslabs < IDN_SLAB_MAXPERDOMAIN) ||
3917c478bd9Sstevel@tonic-gate !IDN_SLAB_MAXPERDOMAIN)
3927c478bd9Sstevel@tonic-gate serrno = smr_slab_alloc_remote(domid, spp);
3937c478bd9Sstevel@tonic-gate else
3947c478bd9Sstevel@tonic-gate serrno = EDQUOT;
3957c478bd9Sstevel@tonic-gate break;
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate default:
3987c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
3997c478bd9Sstevel@tonic-gate "IDN: 301: (ALLOC) unknown slab state (%d) "
4007c478bd9Sstevel@tonic-gate "for domain %d", dp->dslab_state, domid);
4017c478bd9Sstevel@tonic-gate serrno = EINVAL;
4027c478bd9Sstevel@tonic-gate break;
4037c478bd9Sstevel@tonic-gate }
4047c478bd9Sstevel@tonic-gate
4057c478bd9Sstevel@tonic-gate if (*spp == NULL) {
4067c478bd9Sstevel@tonic-gate PR_SMR("%s: failed to allocate %s slab [serrno = %d]\n",
4077c478bd9Sstevel@tonic-gate proc, (idn.localid == IDN_GET_MASTERID()) ?
4087c478bd9Sstevel@tonic-gate "local" : "remote", serrno);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate if (serrno) {
4127c478bd9Sstevel@tonic-gate IDN_GKSTAT_GLOBAL_EVENT(gk_slabfail, gk_slabfail_last);
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate return (serrno);
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate static void
smr_slab_free_local(int domid,smr_slab_t * sp)4197c478bd9Sstevel@tonic-gate smr_slab_free_local(int domid, smr_slab_t *sp)
4207c478bd9Sstevel@tonic-gate {
4217c478bd9Sstevel@tonic-gate int rv;
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate /*
4247c478bd9Sstevel@tonic-gate * Do a slaballoc_put just in case there may have
4257c478bd9Sstevel@tonic-gate * been waiters for slabs for this respective domain
4267c478bd9Sstevel@tonic-gate * before we unreserve this slab.
4277c478bd9Sstevel@tonic-gate */
4287c478bd9Sstevel@tonic-gate rv = smr_slaballoc_put(domid, sp, 0, 0);
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate if (rv == -1) {
4317c478bd9Sstevel@tonic-gate /*
4327c478bd9Sstevel@tonic-gate * Put failed. Must not have been any waiters.
4337c478bd9Sstevel@tonic-gate * Go ahead and unreserve the space.
4347c478bd9Sstevel@tonic-gate */
4357c478bd9Sstevel@tonic-gate smr_slab_unreserve(domid, sp);
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate
4397c478bd9Sstevel@tonic-gate static void
smr_slab_free_remote(int domid,smr_slab_t * sp)4407c478bd9Sstevel@tonic-gate smr_slab_free_remote(int domid, smr_slab_t *sp)
4417c478bd9Sstevel@tonic-gate {
4427c478bd9Sstevel@tonic-gate smr_offset_t slab_offset;
4437c478bd9Sstevel@tonic-gate int slab_size;
4447c478bd9Sstevel@tonic-gate int rv;
4457c478bd9Sstevel@tonic-gate int masterid;
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate ASSERT(domid == idn.localid);
4487c478bd9Sstevel@tonic-gate ASSERT(idn.localid != IDN_GET_MASTERID());
4497c478bd9Sstevel@tonic-gate ASSERT(DSLAB_WRITE_HELD(domid));
4507c478bd9Sstevel@tonic-gate ASSERT(idn_domain[domid].dslab_state == DSLAB_STATE_REMOTE);
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate masterid = IDN_GET_MASTERID();
4537c478bd9Sstevel@tonic-gate
4547c478bd9Sstevel@tonic-gate ASSERT(masterid != IDN_NIL_DOMID);
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate slab_offset = IDN_ADDR2OFFSET(sp->sl_start);
4577c478bd9Sstevel@tonic-gate slab_size = (int)(sp->sl_end - sp->sl_start);
4587c478bd9Sstevel@tonic-gate
4597c478bd9Sstevel@tonic-gate /*
4607c478bd9Sstevel@tonic-gate * Do a slaballoc_put just in case there may have
4617c478bd9Sstevel@tonic-gate * been waiters for slabs for this domain before
4627c478bd9Sstevel@tonic-gate * returning back to the master.
4637c478bd9Sstevel@tonic-gate */
4647c478bd9Sstevel@tonic-gate rv = smr_slaballoc_put(domid, sp, 0, 0);
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate if ((rv == -1) && (masterid != IDN_NIL_DOMID)) {
4677c478bd9Sstevel@tonic-gate /*
4687c478bd9Sstevel@tonic-gate * Put failed. No waiters so free the local data
4697c478bd9Sstevel@tonic-gate * structure ship the SMR range off to the master.
4707c478bd9Sstevel@tonic-gate */
4717c478bd9Sstevel@tonic-gate smr_free_buflist(sp);
4727c478bd9Sstevel@tonic-gate FREESTRUCT(sp, smr_slab_t, 1);
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate IDN_DLOCK_SHARED(masterid);
475d3d50737SRafael Vanoni idn_send_cmd(masterid, IDNCMD_SLABFREE, slab_offset, slab_size,
476d3d50737SRafael Vanoni 0);
4777c478bd9Sstevel@tonic-gate IDN_DUNLOCK(masterid);
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate /*
4827c478bd9Sstevel@tonic-gate * Free up the list of slabs passed
4837c478bd9Sstevel@tonic-gate */
4847c478bd9Sstevel@tonic-gate void
smr_slab_free(int domid,smr_slab_t * sp)4857c478bd9Sstevel@tonic-gate smr_slab_free(int domid, smr_slab_t *sp)
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate smr_slab_t *nsp = NULL;
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate ASSERT(DSLAB_WRITE_HELD(domid));
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate if (sp == NULL)
4927c478bd9Sstevel@tonic-gate return;
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate switch (idn_domain[domid].dslab_state) {
4977c478bd9Sstevel@tonic-gate case DSLAB_STATE_UNKNOWN:
498d3d50737SRafael Vanoni cmn_err(CE_WARN, "IDN: 302: no slab free without a master");
4997c478bd9Sstevel@tonic-gate break;
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate case DSLAB_STATE_LOCAL:
5027c478bd9Sstevel@tonic-gate /*
5037c478bd9Sstevel@tonic-gate * If I'm the master then put the slabs
5047c478bd9Sstevel@tonic-gate * back to the local SMR pool.
5057c478bd9Sstevel@tonic-gate */
5067c478bd9Sstevel@tonic-gate for (; sp; sp = nsp) {
5077c478bd9Sstevel@tonic-gate nsp = sp->sl_next;
5087c478bd9Sstevel@tonic-gate smr_slab_free_local(domid, sp);
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate break;
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate case DSLAB_STATE_REMOTE:
5137c478bd9Sstevel@tonic-gate /*
5147c478bd9Sstevel@tonic-gate * If the domid is my own then I'm freeing
5157c478bd9Sstevel@tonic-gate * a slab back to the Master.
5167c478bd9Sstevel@tonic-gate */
5177c478bd9Sstevel@tonic-gate for (; sp; sp = nsp) {
5187c478bd9Sstevel@tonic-gate nsp = sp->sl_next;
5197c478bd9Sstevel@tonic-gate smr_slab_free_remote(domid, sp);
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate break;
5227c478bd9Sstevel@tonic-gate
5237c478bd9Sstevel@tonic-gate default:
5247c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
525d3d50737SRafael Vanoni "IDN: 301: (FREE) unknown slab state (%d) for domain %d",
5267c478bd9Sstevel@tonic-gate idn_domain[domid].dslab_state, domid);
5277c478bd9Sstevel@tonic-gate break;
5287c478bd9Sstevel@tonic-gate }
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate /*
5327c478bd9Sstevel@tonic-gate * Free up the list of slab data structures ONLY.
5337c478bd9Sstevel@tonic-gate * This is called during a fatal shutdown of the master
5347c478bd9Sstevel@tonic-gate * where we need to garbage collect the locally allocated
5357c478bd9Sstevel@tonic-gate * data structures used to manage slabs allocated to the
5367c478bd9Sstevel@tonic-gate * local domain. Should never be called by a master since
5377c478bd9Sstevel@tonic-gate * the master can do a regular smr_slab_free.
5387c478bd9Sstevel@tonic-gate */
5397c478bd9Sstevel@tonic-gate void
smr_slab_garbage_collection(smr_slab_t * sp)5407c478bd9Sstevel@tonic-gate smr_slab_garbage_collection(smr_slab_t *sp)
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate smr_slab_t *nsp;
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate ASSERT(idn_domain[idn.localid].dvote.v.master == 0);
5457c478bd9Sstevel@tonic-gate
5467c478bd9Sstevel@tonic-gate if (sp == NULL)
5477c478bd9Sstevel@tonic-gate return;
5487c478bd9Sstevel@tonic-gate /*
5497c478bd9Sstevel@tonic-gate * Since this is only ever called by a slave,
5507c478bd9Sstevel@tonic-gate * the slab structure size always contains a buflist.
5517c478bd9Sstevel@tonic-gate */
5527c478bd9Sstevel@tonic-gate for (; sp; sp = nsp) {
5537c478bd9Sstevel@tonic-gate nsp = sp->sl_next;
5547c478bd9Sstevel@tonic-gate smr_free_buflist(sp);
5557c478bd9Sstevel@tonic-gate FREESTRUCT(sp, smr_slab_t, 1);
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate /*
5607c478bd9Sstevel@tonic-gate * Allocate a SMR buffer on behalf of the local domain
5617c478bd9Sstevel@tonic-gate * which is ultimately targeted for the given domain.
5627c478bd9Sstevel@tonic-gate *
5637c478bd9Sstevel@tonic-gate * IMPORTANT: This routine is going to drop the domain rwlock (drwlock)
5647c478bd9Sstevel@tonic-gate * for the domain on whose behalf the request is being
5657c478bd9Sstevel@tonic-gate * made. This routine canNOT block on trying to
5667c478bd9Sstevel@tonic-gate * reacquire the drwlock. If he does block then somebody
5677c478bd9Sstevel@tonic-gate * must have the write lock on the domain which most likely
5687c478bd9Sstevel@tonic-gate * means the domain is going south anyway, so just bail on
5697c478bd9Sstevel@tonic-gate * this buffer. Higher levels will retry if needed.
5707c478bd9Sstevel@tonic-gate *
5717c478bd9Sstevel@tonic-gate * XXX - Support larger than IDN_SMR_BUFSIZE allocations?
5727c478bd9Sstevel@tonic-gate *
5737c478bd9Sstevel@tonic-gate * Returns: A negative return value indicates lock lost on domid.
5747c478bd9Sstevel@tonic-gate * EINVAL, ENOLINK, ENOLCK(internal)
5757c478bd9Sstevel@tonic-gate * smr_slaballoc_wait
5767c478bd9Sstevel@tonic-gate * (EINVAL, ETIMEDOUT)
5777c478bd9Sstevel@tonic-gate * smr_slabwatier_unregister
5787c478bd9Sstevel@tonic-gate * (0, EINVAL, EBUSY, ENOMEM)
5797c478bd9Sstevel@tonic-gate */
5807c478bd9Sstevel@tonic-gate int
smr_buf_alloc(int domid,uint_t len,caddr_t * bufpp)5817c478bd9Sstevel@tonic-gate smr_buf_alloc(int domid, uint_t len, caddr_t *bufpp)
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate register idn_domain_t *dp, *ldp;
5847c478bd9Sstevel@tonic-gate smr_slab_t *sp;
5857c478bd9Sstevel@tonic-gate caddr_t bufp = NULL;
5867c478bd9Sstevel@tonic-gate int serrno;
5877c478bd9Sstevel@tonic-gate procname_t proc = "smr_buf_alloc";
5887c478bd9Sstevel@tonic-gate
5897c478bd9Sstevel@tonic-gate dp = &idn_domain[domid];
5907c478bd9Sstevel@tonic-gate /*
5917c478bd9Sstevel@tonic-gate * Local domain can only allocate on behalf of
5927c478bd9Sstevel@tonic-gate * itself if this is a priviledged call and the
5937c478bd9Sstevel@tonic-gate * caller is the master.
5947c478bd9Sstevel@tonic-gate */
5957c478bd9Sstevel@tonic-gate ASSERT((domid != idn.localid) && (domid != IDN_NIL_DOMID));
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate *bufpp = NULL;
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate if (len > IDN_DATA_SIZE) {
6007c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
601bf30efa4Smathue "IDN: 303: buffer len %d > IDN_DATA_SIZE (%lu)",
6027c478bd9Sstevel@tonic-gate len, IDN_DATA_SIZE);
6037c478bd9Sstevel@tonic-gate IDN_GKSTAT_GLOBAL_EVENT(gk_buffail, gk_buffail_last);
6047c478bd9Sstevel@tonic-gate return (EINVAL);
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gate /*
6087c478bd9Sstevel@tonic-gate * Need to go to my local slab list to find
6097c478bd9Sstevel@tonic-gate * a buffer.
6107c478bd9Sstevel@tonic-gate */
6117c478bd9Sstevel@tonic-gate ldp = &idn_domain[idn.localid];
6127c478bd9Sstevel@tonic-gate /*
6137c478bd9Sstevel@tonic-gate * Now we loop trying to locate a buffer out of our
6147c478bd9Sstevel@tonic-gate * slabs. We continue this until either we find a
6157c478bd9Sstevel@tonic-gate * buffer or we're unable to allocate a slab. Note
6167c478bd9Sstevel@tonic-gate * that new slabs are allocated to the front.
6177c478bd9Sstevel@tonic-gate */
6187c478bd9Sstevel@tonic-gate DSLAB_LOCK_SHARED(idn.localid);
6197c478bd9Sstevel@tonic-gate sp = ldp->dslab;
6207c478bd9Sstevel@tonic-gate do {
6217c478bd9Sstevel@tonic-gate int spl, all_empty;
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate if (sp == NULL) {
6247c478bd9Sstevel@tonic-gate if ((serrno = smr_slab_alloc(idn.localid, &sp)) != 0) {
6257c478bd9Sstevel@tonic-gate PR_SMR("%s:%d: failed to allocate "
6267c478bd9Sstevel@tonic-gate "slab [serrno = %d]",
6277c478bd9Sstevel@tonic-gate proc, domid, serrno);
6287c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid);
6297c478bd9Sstevel@tonic-gate IDN_GKSTAT_GLOBAL_EVENT(gk_buffail,
6307c478bd9Sstevel@tonic-gate gk_buffail_last);
6317c478bd9Sstevel@tonic-gate return (serrno);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate /*
6347c478bd9Sstevel@tonic-gate * Of course, the world may have changed while
6357c478bd9Sstevel@tonic-gate * we dropped the lock. Better make sure we're
6367c478bd9Sstevel@tonic-gate * still established.
6377c478bd9Sstevel@tonic-gate */
6387c478bd9Sstevel@tonic-gate if (dp->dstate != IDNDS_CONNECTED) {
6397c478bd9Sstevel@tonic-gate PR_SMR("%s:%d: state changed during slab "
6407c478bd9Sstevel@tonic-gate "alloc (dstate = %s)\n",
6417c478bd9Sstevel@tonic-gate proc, domid, idnds_str[dp->dstate]);
6427c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid);
6437c478bd9Sstevel@tonic-gate IDN_GKSTAT_GLOBAL_EVENT(gk_buffail,
6447c478bd9Sstevel@tonic-gate gk_buffail_last);
6457c478bd9Sstevel@tonic-gate return (ENOLINK);
6467c478bd9Sstevel@tonic-gate }
6477c478bd9Sstevel@tonic-gate /*
6487c478bd9Sstevel@tonic-gate * We were able to allocate a slab. Should
6497c478bd9Sstevel@tonic-gate * be at the front of the list, spin again.
6507c478bd9Sstevel@tonic-gate */
6517c478bd9Sstevel@tonic-gate sp = ldp->dslab;
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate /*
6547c478bd9Sstevel@tonic-gate * If we have reached here then we have a slab!
6557c478bd9Sstevel@tonic-gate * Hopefully there are free bufs there :-o
6567c478bd9Sstevel@tonic-gate */
6577c478bd9Sstevel@tonic-gate spl = splhi();
6587c478bd9Sstevel@tonic-gate all_empty = 1;
6597c478bd9Sstevel@tonic-gate for (; sp && !bufp; sp = sp->sl_next) {
6607c478bd9Sstevel@tonic-gate smr_slabbuf_t *bp;
6617c478bd9Sstevel@tonic-gate
6627c478bd9Sstevel@tonic-gate if (sp->sl_free == NULL)
6637c478bd9Sstevel@tonic-gate continue;
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate if (!lock_try(&sp->sl_lock)) {
6667c478bd9Sstevel@tonic-gate all_empty = 0;
6677c478bd9Sstevel@tonic-gate continue;
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate
6707c478bd9Sstevel@tonic-gate if ((bp = sp->sl_free) == NULL) {
6717c478bd9Sstevel@tonic-gate lock_clear(&sp->sl_lock);
6727c478bd9Sstevel@tonic-gate continue;
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate
6757c478bd9Sstevel@tonic-gate sp->sl_free = bp->sb_next;
6767c478bd9Sstevel@tonic-gate bp->sb_next = sp->sl_inuse;
6777c478bd9Sstevel@tonic-gate sp->sl_inuse = bp;
6787c478bd9Sstevel@tonic-gate /*
6797c478bd9Sstevel@tonic-gate * Found a free buffer.
6807c478bd9Sstevel@tonic-gate */
6817c478bd9Sstevel@tonic-gate bp->sb_domid = domid;
6827c478bd9Sstevel@tonic-gate bufp = bp->sb_bufp;
6837c478bd9Sstevel@tonic-gate lock_clear(&sp->sl_lock);
6847c478bd9Sstevel@tonic-gate }
6857c478bd9Sstevel@tonic-gate splx(spl);
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate if (!all_empty && !bufp) {
6887c478bd9Sstevel@tonic-gate /*
6897c478bd9Sstevel@tonic-gate * If we still haven't found a buffer, but
6907c478bd9Sstevel@tonic-gate * there's still possibly a buffer available,
6917c478bd9Sstevel@tonic-gate * then try again. Only if we're absolutely
6927c478bd9Sstevel@tonic-gate * sure all slabs are empty do we attempt
6937c478bd9Sstevel@tonic-gate * to allocate a new one.
6947c478bd9Sstevel@tonic-gate */
6957c478bd9Sstevel@tonic-gate sp = ldp->dslab;
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate } while (bufp == NULL);
6987c478bd9Sstevel@tonic-gate
6997c478bd9Sstevel@tonic-gate *bufpp = bufp;
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate ATOMIC_INC(dp->dio);
7027c478bd9Sstevel@tonic-gate
7037c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid);
7047c478bd9Sstevel@tonic-gate
7057c478bd9Sstevel@tonic-gate return (0);
7067c478bd9Sstevel@tonic-gate }
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate /*
7097c478bd9Sstevel@tonic-gate * Free a buffer allocated to the local domain back to
7107c478bd9Sstevel@tonic-gate * its respective slab. Slabs are freed via the slab-reap command.
7117c478bd9Sstevel@tonic-gate * XXX - Support larger than IDN_SMR_BUFSIZE allocations?
7127c478bd9Sstevel@tonic-gate */
7137c478bd9Sstevel@tonic-gate int
smr_buf_free(int domid,caddr_t bufp,uint_t len)7147c478bd9Sstevel@tonic-gate smr_buf_free(int domid, caddr_t bufp, uint_t len)
7157c478bd9Sstevel@tonic-gate {
7167c478bd9Sstevel@tonic-gate register smr_slab_t *sp;
7177c478bd9Sstevel@tonic-gate smr_slabbuf_t *bp, **bpp;
7187c478bd9Sstevel@tonic-gate idn_domain_t *ldp;
7197c478bd9Sstevel@tonic-gate int buffreed;
7207c478bd9Sstevel@tonic-gate int lockheld = (len == (uint_t)-1);
7217c478bd9Sstevel@tonic-gate
7227c478bd9Sstevel@tonic-gate /*
7237c478bd9Sstevel@tonic-gate * We should never be free'ing a buffer on
7247c478bd9Sstevel@tonic-gate * behalf of ourselves as we are never the
7257c478bd9Sstevel@tonic-gate * target for allocated SMR buffers.
7267c478bd9Sstevel@tonic-gate */
7277c478bd9Sstevel@tonic-gate ASSERT(domid != idn.localid);
7287c478bd9Sstevel@tonic-gate
7297c478bd9Sstevel@tonic-gate sp = NULL;
7307c478bd9Sstevel@tonic-gate buffreed = 0;
7317c478bd9Sstevel@tonic-gate ldp = &idn_domain[idn.localid];
7327c478bd9Sstevel@tonic-gate
7337c478bd9Sstevel@tonic-gate DSLAB_LOCK_SHARED(idn.localid);
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate if (((uintptr_t)bufp & (IDN_SMR_BUFSIZE-1)) &&
7367c478bd9Sstevel@tonic-gate (IDN_ADDR2OFFSET(bufp) % IDN_SMR_BUFSIZE)) {
7377c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
738bf30efa4Smathue "IDN: 304: buffer (0x%p) from domain %d not on a "
739*07d06da5SSurya Prakki "%d boundary", (void *)bufp, domid, IDN_SMR_BUFSIZE);
7407c478bd9Sstevel@tonic-gate goto bfdone;
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate if (!lockheld && (len > IDN_DATA_SIZE)) {
7437c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
7447c478bd9Sstevel@tonic-gate "IDN: 305: buffer length (%d) from domain %d greater "
745bf30efa4Smathue "than IDN_DATA_SIZE (%lu)",
7467c478bd9Sstevel@tonic-gate len, domid, IDN_DATA_SIZE);
7477c478bd9Sstevel@tonic-gate goto bfdone;
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate
7507c478bd9Sstevel@tonic-gate for (sp = ldp->dslab; sp; sp = sp->sl_next)
7517c478bd9Sstevel@tonic-gate if ((bufp >= sp->sl_start) && (bufp < sp->sl_end))
7527c478bd9Sstevel@tonic-gate break;
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate if (sp) {
7557c478bd9Sstevel@tonic-gate int spl;
7567c478bd9Sstevel@tonic-gate
7577c478bd9Sstevel@tonic-gate spl = splhi();
7587c478bd9Sstevel@tonic-gate while (!lock_try(&sp->sl_lock))
7597c478bd9Sstevel@tonic-gate ;
7607c478bd9Sstevel@tonic-gate bpp = &sp->sl_inuse;
7617c478bd9Sstevel@tonic-gate for (bp = *bpp; bp; bp = *bpp) {
7627c478bd9Sstevel@tonic-gate if (bp->sb_bufp == bufp)
7637c478bd9Sstevel@tonic-gate break;
7647c478bd9Sstevel@tonic-gate bpp = &bp->sb_next;
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate if (bp) {
7677c478bd9Sstevel@tonic-gate ASSERT(bp->sb_domid == domid);
7687c478bd9Sstevel@tonic-gate buffreed++;
7697c478bd9Sstevel@tonic-gate bp->sb_domid = IDN_NIL_DOMID;
7707c478bd9Sstevel@tonic-gate *bpp = bp->sb_next;
7717c478bd9Sstevel@tonic-gate bp->sb_next = sp->sl_free;
7727c478bd9Sstevel@tonic-gate sp->sl_free = bp;
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate lock_clear(&sp->sl_lock);
7757c478bd9Sstevel@tonic-gate splx(spl);
7767c478bd9Sstevel@tonic-gate }
7777c478bd9Sstevel@tonic-gate bfdone:
7787c478bd9Sstevel@tonic-gate if (buffreed) {
7797c478bd9Sstevel@tonic-gate ATOMIC_DEC(idn_domain[domid].dio);
7807c478bd9Sstevel@tonic-gate DIOCHECK(domid);
7817c478bd9Sstevel@tonic-gate } else {
7827c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
7837c478bd9Sstevel@tonic-gate "IDN: 306: unknown buffer (0x%p) from domain %d",
784*07d06da5SSurya Prakki (void *)bufp, domid);
7857c478bd9Sstevel@tonic-gate ATOMIC_INC(idn_domain[domid].dioerr);
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate
7887c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid);
7897c478bd9Sstevel@tonic-gate
7907c478bd9Sstevel@tonic-gate return (sp ? 0 : -1);
7917c478bd9Sstevel@tonic-gate }
7927c478bd9Sstevel@tonic-gate
7937c478bd9Sstevel@tonic-gate /*
7947c478bd9Sstevel@tonic-gate * Alternative interface to smr_buf_free, but with local drwlock
7957c478bd9Sstevel@tonic-gate * held.
7967c478bd9Sstevel@tonic-gate */
7977c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
7987c478bd9Sstevel@tonic-gate int
smr_buf_free_locked(int domid,caddr_t bufp,uint_t len)7997c478bd9Sstevel@tonic-gate smr_buf_free_locked(int domid, caddr_t bufp, uint_t len)
8007c478bd9Sstevel@tonic-gate {
8017c478bd9Sstevel@tonic-gate return (smr_buf_free(domid, bufp, (uint_t)-1));
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate
8047c478bd9Sstevel@tonic-gate /*
8057c478bd9Sstevel@tonic-gate * Free any and all buffers associated with the given domain.
8067c478bd9Sstevel@tonic-gate * Assumption is that domain is dead and buffers are not in use.
8077c478bd9Sstevel@tonic-gate * Returns: Number of buffers freed.
8087c478bd9Sstevel@tonic-gate * -1 if error.
8097c478bd9Sstevel@tonic-gate */
8107c478bd9Sstevel@tonic-gate int
smr_buf_free_all(int domid)8117c478bd9Sstevel@tonic-gate smr_buf_free_all(int domid)
8127c478bd9Sstevel@tonic-gate {
8137c478bd9Sstevel@tonic-gate register smr_slab_t *sp;
8147c478bd9Sstevel@tonic-gate register smr_slabbuf_t *bp, **bpp;
8157c478bd9Sstevel@tonic-gate idn_domain_t *ldp;
8167c478bd9Sstevel@tonic-gate int nbufsfreed = 0;
8177c478bd9Sstevel@tonic-gate procname_t proc = "smr_buf_free_all";
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate /*
8207c478bd9Sstevel@tonic-gate * We should never be free'ing buffers on
8217c478bd9Sstevel@tonic-gate * behalf of ourself
8227c478bd9Sstevel@tonic-gate */
8237c478bd9Sstevel@tonic-gate ASSERT(domid != idn.localid);
8247c478bd9Sstevel@tonic-gate
8257c478bd9Sstevel@tonic-gate if (!VALID_DOMAINID(domid)) {
826d3d50737SRafael Vanoni cmn_err(CE_WARN, "IDN: 307: domain ID (%d) invalid", domid);
8277c478bd9Sstevel@tonic-gate return (-1);
8287c478bd9Sstevel@tonic-gate }
8297c478bd9Sstevel@tonic-gate
8307c478bd9Sstevel@tonic-gate ldp = &idn_domain[idn.localid];
8317c478bd9Sstevel@tonic-gate
8327c478bd9Sstevel@tonic-gate /*
8337c478bd9Sstevel@tonic-gate * We grab the writer lock so that we don't have any
8347c478bd9Sstevel@tonic-gate * competition during a "free-all" call.
8357c478bd9Sstevel@tonic-gate * No need to grab individual slab locks when holding
8367c478bd9Sstevel@tonic-gate * dslab(writer).
8377c478bd9Sstevel@tonic-gate */
8387c478bd9Sstevel@tonic-gate DSLAB_LOCK_EXCL(idn.localid);
8397c478bd9Sstevel@tonic-gate
8407c478bd9Sstevel@tonic-gate for (sp = ldp->dslab; sp; sp = sp->sl_next) {
8417c478bd9Sstevel@tonic-gate bpp = &sp->sl_inuse;
8427c478bd9Sstevel@tonic-gate for (bp = *bpp; bp; bp = *bpp) {
8437c478bd9Sstevel@tonic-gate if (bp->sb_domid == domid) {
8447c478bd9Sstevel@tonic-gate bp->sb_domid = IDN_NIL_DOMID;
8457c478bd9Sstevel@tonic-gate *bpp = bp->sb_next;
8467c478bd9Sstevel@tonic-gate bp->sb_next = sp->sl_free;
8477c478bd9Sstevel@tonic-gate sp->sl_free = bp;
8487c478bd9Sstevel@tonic-gate nbufsfreed++;
8497c478bd9Sstevel@tonic-gate } else {
8507c478bd9Sstevel@tonic-gate bpp = &bp->sb_next;
8517c478bd9Sstevel@tonic-gate }
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate }
8547c478bd9Sstevel@tonic-gate
8557c478bd9Sstevel@tonic-gate if (nbufsfreed > 0) {
8567c478bd9Sstevel@tonic-gate ATOMIC_SUB(idn_domain[domid].dio, nbufsfreed);
8577c478bd9Sstevel@tonic-gate idn_domain[domid].dioerr = 0;
8587c478bd9Sstevel@tonic-gate DIOCHECK(domid);
8597c478bd9Sstevel@tonic-gate }
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid);
8627c478bd9Sstevel@tonic-gate
863d3d50737SRafael Vanoni PR_SMR("%s: freed %d buffers for domain %d\n", proc, nbufsfreed, domid);
8647c478bd9Sstevel@tonic-gate
8657c478bd9Sstevel@tonic-gate return (nbufsfreed);
8667c478bd9Sstevel@tonic-gate }
8677c478bd9Sstevel@tonic-gate
8687c478bd9Sstevel@tonic-gate int
smr_buf_reclaim(int domid,int nbufs)8697c478bd9Sstevel@tonic-gate smr_buf_reclaim(int domid, int nbufs)
8707c478bd9Sstevel@tonic-gate {
8717c478bd9Sstevel@tonic-gate int num_reclaimed = 0;
8727c478bd9Sstevel@tonic-gate idn_domain_t *ldp, *dp;
8737c478bd9Sstevel@tonic-gate procname_t proc = "smr_buf_reclaim";
8747c478bd9Sstevel@tonic-gate
8757c478bd9Sstevel@tonic-gate ldp = &idn_domain[idn.localid];
8767c478bd9Sstevel@tonic-gate dp = &idn_domain[domid];
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate ASSERT(domid != idn.localid);
8797c478bd9Sstevel@tonic-gate
8807c478bd9Sstevel@tonic-gate if (ATOMIC_CAS(&dp->dreclaim_inprogress, 0, 1)) {
8817c478bd9Sstevel@tonic-gate /*
8827c478bd9Sstevel@tonic-gate * Reclaim is already in progress, don't
8837c478bd9Sstevel@tonic-gate * bother.
8847c478bd9Sstevel@tonic-gate */
8857c478bd9Sstevel@tonic-gate PR_DATA("%s: reclaim already in progress\n", proc);
8867c478bd9Sstevel@tonic-gate return (0);
8877c478bd9Sstevel@tonic-gate }
8887c478bd9Sstevel@tonic-gate
889d3d50737SRafael Vanoni PR_SMR("%s: requested %d buffers from domain %d\n", proc, nbufs, domid);
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate if (dp->dio && nbufs) {
8927c478bd9Sstevel@tonic-gate register smr_slab_t *sp;
8937c478bd9Sstevel@tonic-gate int spl;
8947c478bd9Sstevel@tonic-gate
8957c478bd9Sstevel@tonic-gate DSLAB_LOCK_SHARED(idn.localid);
8967c478bd9Sstevel@tonic-gate spl = splhi();
8977c478bd9Sstevel@tonic-gate for (sp = ldp->dslab; sp && nbufs; sp = sp->sl_next) {
8987c478bd9Sstevel@tonic-gate register smr_slabbuf_t *bp, **bpp;
8997c478bd9Sstevel@tonic-gate
9007c478bd9Sstevel@tonic-gate if (sp->sl_inuse == NULL)
9017c478bd9Sstevel@tonic-gate continue;
9027c478bd9Sstevel@tonic-gate
9037c478bd9Sstevel@tonic-gate if (!lock_try(&sp->sl_lock))
9047c478bd9Sstevel@tonic-gate continue;
9057c478bd9Sstevel@tonic-gate
9067c478bd9Sstevel@tonic-gate if (sp->sl_inuse == NULL) {
9077c478bd9Sstevel@tonic-gate lock_clear(&sp->sl_lock);
9087c478bd9Sstevel@tonic-gate continue;
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate bpp = &sp->sl_inuse;
9127c478bd9Sstevel@tonic-gate for (bp = *bpp; bp && nbufs; bp = *bpp) {
9137c478bd9Sstevel@tonic-gate if (bp->sb_domid == domid) {
9147c478bd9Sstevel@tonic-gate /*
9157c478bd9Sstevel@tonic-gate * Buffer no longer in use,
9167c478bd9Sstevel@tonic-gate * reclaim it.
9177c478bd9Sstevel@tonic-gate */
9187c478bd9Sstevel@tonic-gate bp->sb_domid = IDN_NIL_DOMID;
9197c478bd9Sstevel@tonic-gate *bpp = bp->sb_next;
9207c478bd9Sstevel@tonic-gate bp->sb_next = sp->sl_free;
9217c478bd9Sstevel@tonic-gate sp->sl_free = bp;
9227c478bd9Sstevel@tonic-gate num_reclaimed++;
9237c478bd9Sstevel@tonic-gate nbufs--;
9247c478bd9Sstevel@tonic-gate } else {
9257c478bd9Sstevel@tonic-gate bpp = &bp->sb_next;
9267c478bd9Sstevel@tonic-gate }
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate lock_clear(&sp->sl_lock);
9297c478bd9Sstevel@tonic-gate }
9307c478bd9Sstevel@tonic-gate splx(spl);
9317c478bd9Sstevel@tonic-gate
9327c478bd9Sstevel@tonic-gate if (num_reclaimed > 0) {
9337c478bd9Sstevel@tonic-gate ATOMIC_SUB(dp->dio, num_reclaimed);
9347c478bd9Sstevel@tonic-gate DIOCHECK(domid);
9357c478bd9Sstevel@tonic-gate }
9367c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid);
9377c478bd9Sstevel@tonic-gate }
9387c478bd9Sstevel@tonic-gate
9397c478bd9Sstevel@tonic-gate PR_SMR("%s: reclaimed %d buffers from domain %d\n",
9407c478bd9Sstevel@tonic-gate proc, num_reclaimed, domid);
9417c478bd9Sstevel@tonic-gate
9427c478bd9Sstevel@tonic-gate return (num_reclaimed);
9437c478bd9Sstevel@tonic-gate }
9447c478bd9Sstevel@tonic-gate
9457c478bd9Sstevel@tonic-gate /*
9467c478bd9Sstevel@tonic-gate * Returns 1 If any buffers are locked for the given slab.
9477c478bd9Sstevel@tonic-gate * 0 If all buffers are free for the given slab.
9487c478bd9Sstevel@tonic-gate *
9497c478bd9Sstevel@tonic-gate * The caller is assumed to have the slab protected so that no
9507c478bd9Sstevel@tonic-gate * new allocations are attempted from it. Also, this is only
9517c478bd9Sstevel@tonic-gate * valid to be called with respect to slabs that were allocated
9527c478bd9Sstevel@tonic-gate * on behalf of the local domain, i.e. the master is not expected
9537c478bd9Sstevel@tonic-gate * to call this function with (slave) slab "representatives".
9547c478bd9Sstevel@tonic-gate */
9557c478bd9Sstevel@tonic-gate int
smr_slab_busy(smr_slab_t * sp)9567c478bd9Sstevel@tonic-gate smr_slab_busy(smr_slab_t *sp)
9577c478bd9Sstevel@tonic-gate {
9587c478bd9Sstevel@tonic-gate return ((sp && sp->sl_inuse) ? 1 : 0);
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate
9617c478bd9Sstevel@tonic-gate int
smr_slabwaiter_init()9627c478bd9Sstevel@tonic-gate smr_slabwaiter_init()
9637c478bd9Sstevel@tonic-gate {
9647c478bd9Sstevel@tonic-gate register int i;
9657c478bd9Sstevel@tonic-gate struct slabwaiter *wp;
9667c478bd9Sstevel@tonic-gate
9677c478bd9Sstevel@tonic-gate if (idn.slabwaiter != NULL)
9687c478bd9Sstevel@tonic-gate return (0);
9697c478bd9Sstevel@tonic-gate
9707c478bd9Sstevel@tonic-gate /*
9717c478bd9Sstevel@tonic-gate * Initialize the slab waiting area for MAX_DOMAINS.
9727c478bd9Sstevel@tonic-gate */
9737c478bd9Sstevel@tonic-gate idn.slabwaiter = GETSTRUCT(struct slabwaiter, MAX_DOMAINS);
9747c478bd9Sstevel@tonic-gate wp = idn.slabwaiter;
9757c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_DOMAINS; wp++, i++) {
9767c478bd9Sstevel@tonic-gate wp->w_closed = 0;
9777c478bd9Sstevel@tonic-gate mutex_init(&wp->w_mutex, NULL, MUTEX_DEFAULT, NULL);
9787c478bd9Sstevel@tonic-gate cv_init(&wp->w_cv, NULL, CV_DEFAULT, NULL);
9797c478bd9Sstevel@tonic-gate }
9807c478bd9Sstevel@tonic-gate
9817c478bd9Sstevel@tonic-gate return (0);
9827c478bd9Sstevel@tonic-gate }
9837c478bd9Sstevel@tonic-gate
9847c478bd9Sstevel@tonic-gate void
smr_slabwaiter_deinit()9857c478bd9Sstevel@tonic-gate smr_slabwaiter_deinit()
9867c478bd9Sstevel@tonic-gate {
9877c478bd9Sstevel@tonic-gate register int i;
9887c478bd9Sstevel@tonic-gate struct slabwaiter *wp;
9897c478bd9Sstevel@tonic-gate
9907c478bd9Sstevel@tonic-gate if ((wp = idn.slabwaiter) == NULL)
9917c478bd9Sstevel@tonic-gate return;
9927c478bd9Sstevel@tonic-gate
9937c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_DOMAINS; wp++, i++) {
9947c478bd9Sstevel@tonic-gate ASSERT(wp->w_nwaiters == 0);
9957c478bd9Sstevel@tonic-gate ASSERT(wp->w_sp == NULL);
9967c478bd9Sstevel@tonic-gate cv_destroy(&wp->w_cv);
9977c478bd9Sstevel@tonic-gate mutex_destroy(&wp->w_mutex);
9987c478bd9Sstevel@tonic-gate }
9997c478bd9Sstevel@tonic-gate
10007c478bd9Sstevel@tonic-gate FREESTRUCT(idn.slabwaiter, struct slabwaiter, MAX_DOMAINS);
10017c478bd9Sstevel@tonic-gate idn.slabwaiter = NULL;
10027c478bd9Sstevel@tonic-gate }
10037c478bd9Sstevel@tonic-gate
10047c478bd9Sstevel@tonic-gate void
smr_slabwaiter_open(domainset_t domset)10057c478bd9Sstevel@tonic-gate smr_slabwaiter_open(domainset_t domset)
10067c478bd9Sstevel@tonic-gate {
10077c478bd9Sstevel@tonic-gate int d;
10087c478bd9Sstevel@tonic-gate struct slabwaiter *wp;
10097c478bd9Sstevel@tonic-gate
10107c478bd9Sstevel@tonic-gate if ((domset == 0) || !idn.slabwaiter)
10117c478bd9Sstevel@tonic-gate return;
10127c478bd9Sstevel@tonic-gate
10137c478bd9Sstevel@tonic-gate wp = idn.slabwaiter;
10147c478bd9Sstevel@tonic-gate
10157c478bd9Sstevel@tonic-gate for (d = 0; d < MAX_DOMAINS; wp++, d++) {
10167c478bd9Sstevel@tonic-gate if (!DOMAIN_IN_SET(domset, d))
10177c478bd9Sstevel@tonic-gate continue;
10187c478bd9Sstevel@tonic-gate mutex_enter(&wp->w_mutex);
10197c478bd9Sstevel@tonic-gate wp->w_closed = 0;
10207c478bd9Sstevel@tonic-gate mutex_exit(&wp->w_mutex);
10217c478bd9Sstevel@tonic-gate }
10227c478bd9Sstevel@tonic-gate }
10237c478bd9Sstevel@tonic-gate
10247c478bd9Sstevel@tonic-gate void
smr_slabwaiter_close(domainset_t domset)10257c478bd9Sstevel@tonic-gate smr_slabwaiter_close(domainset_t domset)
10267c478bd9Sstevel@tonic-gate {
10277c478bd9Sstevel@tonic-gate int d;
10287c478bd9Sstevel@tonic-gate struct slabwaiter *wp;
10297c478bd9Sstevel@tonic-gate
10307c478bd9Sstevel@tonic-gate if ((domset == 0) || !idn.slabwaiter)
10317c478bd9Sstevel@tonic-gate return;
10327c478bd9Sstevel@tonic-gate
10337c478bd9Sstevel@tonic-gate wp = idn.slabwaiter;
10347c478bd9Sstevel@tonic-gate
10357c478bd9Sstevel@tonic-gate for (d = 0; d < MAX_DOMAINS; wp++, d++) {
10367c478bd9Sstevel@tonic-gate if (!DOMAIN_IN_SET(domset, d))
10377c478bd9Sstevel@tonic-gate continue;
10387c478bd9Sstevel@tonic-gate mutex_enter(&wp->w_mutex);
10397c478bd9Sstevel@tonic-gate wp->w_closed = 1;
10407c478bd9Sstevel@tonic-gate cv_broadcast(&wp->w_cv);
10417c478bd9Sstevel@tonic-gate mutex_exit(&wp->w_mutex);
10427c478bd9Sstevel@tonic-gate }
10437c478bd9Sstevel@tonic-gate }
10447c478bd9Sstevel@tonic-gate
10457c478bd9Sstevel@tonic-gate /*
10467c478bd9Sstevel@tonic-gate * Register the caller with the waiting list for the
10477c478bd9Sstevel@tonic-gate * given domain.
10487c478bd9Sstevel@tonic-gate *
10497c478bd9Sstevel@tonic-gate * Protocol:
10507c478bd9Sstevel@tonic-gate * 1st Local requester: register -> alloc ->
10517c478bd9Sstevel@tonic-gate * put(wakeup|xdc) -> unregister
10527c478bd9Sstevel@tonic-gate * Nth Local requester: register -> wait
10537c478bd9Sstevel@tonic-gate * 1st Remote requester: register -> xdc -> wait
10547c478bd9Sstevel@tonic-gate * Nth Remote requester: register -> wait
10557c478bd9Sstevel@tonic-gate *
10567c478bd9Sstevel@tonic-gate * Remote Responder: local alloc -> put(xdc)
10577c478bd9Sstevel@tonic-gate * Local Handler: xdc -> put(wakeup)
10587c478bd9Sstevel@tonic-gate *
10597c478bd9Sstevel@tonic-gate * E.g. A standard slave allocation request:
10607c478bd9Sstevel@tonic-gate * slave master
10617c478bd9Sstevel@tonic-gate * ----- ------
10627c478bd9Sstevel@tonic-gate * idn_slab_alloc(remote)
10637c478bd9Sstevel@tonic-gate * - register
10647c478bd9Sstevel@tonic-gate * - xdc -> idn_handler
10657c478bd9Sstevel@tonic-gate * - wait ...
10667c478bd9Sstevel@tonic-gate * idn_slab_alloc(local)
10677c478bd9Sstevel@tonic-gate * - register
10687c478bd9Sstevel@tonic-gate * - alloc
10697c478bd9Sstevel@tonic-gate * - put
10707c478bd9Sstevel@tonic-gate * . wakeup [local]
10717c478bd9Sstevel@tonic-gate * - unregister
10727c478bd9Sstevel@tonic-gate * idn_handler <- - xdc
10737c478bd9Sstevel@tonic-gate * - put DONE
10747c478bd9Sstevel@tonic-gate * . wakeup [local]
10757c478bd9Sstevel@tonic-gate * |
10767c478bd9Sstevel@tonic-gate * V
10777c478bd9Sstevel@tonic-gate * - wait
10787c478bd9Sstevel@tonic-gate * . unregister
10797c478bd9Sstevel@tonic-gate * DONE
10807c478bd9Sstevel@tonic-gate */
10817c478bd9Sstevel@tonic-gate static int
smr_slabwaiter_register(int domid)10827c478bd9Sstevel@tonic-gate smr_slabwaiter_register(int domid)
10837c478bd9Sstevel@tonic-gate {
10847c478bd9Sstevel@tonic-gate struct slabwaiter *wp;
10857c478bd9Sstevel@tonic-gate int nwait;
10867c478bd9Sstevel@tonic-gate procname_t proc = "smr_slabwaiter_register";
10877c478bd9Sstevel@tonic-gate
10887c478bd9Sstevel@tonic-gate
10897c478bd9Sstevel@tonic-gate ASSERT(domid != IDN_NIL_DOMID);
10907c478bd9Sstevel@tonic-gate
10917c478bd9Sstevel@tonic-gate ASSERT(DSLAB_READ_HELD(domid));
10927c478bd9Sstevel@tonic-gate
10937c478bd9Sstevel@tonic-gate wp = &idn.slabwaiter[domid];
10947c478bd9Sstevel@tonic-gate
10957c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&wp->w_mutex));
10967c478bd9Sstevel@tonic-gate
10977c478bd9Sstevel@tonic-gate mutex_enter(&wp->w_mutex);
10987c478bd9Sstevel@tonic-gate
10997c478bd9Sstevel@tonic-gate nwait = ++(wp->w_nwaiters);
11007c478bd9Sstevel@tonic-gate ASSERT(nwait > 0);
11017c478bd9Sstevel@tonic-gate
1102d3d50737SRafael Vanoni PR_SMR("%s: domain = %d, (new)nwaiters = %d\n", proc, domid, nwait);
11037c478bd9Sstevel@tonic-gate
11047c478bd9Sstevel@tonic-gate if (nwait > 1) {
11057c478bd9Sstevel@tonic-gate /*
11067c478bd9Sstevel@tonic-gate * There are already waiters for slab allocations
11077c478bd9Sstevel@tonic-gate * with respect to this domain.
11087c478bd9Sstevel@tonic-gate */
11097c478bd9Sstevel@tonic-gate PR_SMR("%s: existing waiters for slabs for domain %d\n",
11107c478bd9Sstevel@tonic-gate proc, domid);
11117c478bd9Sstevel@tonic-gate mutex_exit(&wp->w_mutex);
11127c478bd9Sstevel@tonic-gate
11137c478bd9Sstevel@tonic-gate return (nwait);
11147c478bd9Sstevel@tonic-gate }
11157c478bd9Sstevel@tonic-gate PR_SMR("%s: initial waiter for slabs for domain %d\n", proc, domid);
11167c478bd9Sstevel@tonic-gate /*
11177c478bd9Sstevel@tonic-gate * We are the first requester of a slab allocation for this
11187c478bd9Sstevel@tonic-gate * respective domain. Need to prep waiting area for
11197c478bd9Sstevel@tonic-gate * subsequent arrival of a slab.
11207c478bd9Sstevel@tonic-gate */
11217c478bd9Sstevel@tonic-gate wp->w_sp = NULL;
11227c478bd9Sstevel@tonic-gate wp->w_done = 0;
11237c478bd9Sstevel@tonic-gate wp->w_serrno = 0;
11247c478bd9Sstevel@tonic-gate
11257c478bd9Sstevel@tonic-gate mutex_exit(&wp->w_mutex);
11267c478bd9Sstevel@tonic-gate
11277c478bd9Sstevel@tonic-gate return (nwait);
11287c478bd9Sstevel@tonic-gate }
11297c478bd9Sstevel@tonic-gate
11307c478bd9Sstevel@tonic-gate /*
11317c478bd9Sstevel@tonic-gate * It is assumed that the caller had previously registered,
11327c478bd9Sstevel@tonic-gate * but wakeup did not occur due to caller never waiting.
11337c478bd9Sstevel@tonic-gate * Thus, slaballoc mutex is still held by caller.
11347c478bd9Sstevel@tonic-gate *
11357c478bd9Sstevel@tonic-gate * Returns: 0
11367c478bd9Sstevel@tonic-gate * EINVAL
11377c478bd9Sstevel@tonic-gate * EBUSY
11387c478bd9Sstevel@tonic-gate * w_serrno (smr_slaballoc_put)
11397c478bd9Sstevel@tonic-gate * (0, ENOLCK, ENOMEM, EDQUOT, EBUSY, ECANCELED)
11407c478bd9Sstevel@tonic-gate */
11417c478bd9Sstevel@tonic-gate static int
smr_slabwaiter_unregister(int domid,smr_slab_t ** spp)11427c478bd9Sstevel@tonic-gate smr_slabwaiter_unregister(int domid, smr_slab_t **spp)
11437c478bd9Sstevel@tonic-gate {
11447c478bd9Sstevel@tonic-gate struct slabwaiter *wp;
11457c478bd9Sstevel@tonic-gate int serrno = 0;
11467c478bd9Sstevel@tonic-gate procname_t proc = "smr_slabwaiter_unregister";
11477c478bd9Sstevel@tonic-gate
11487c478bd9Sstevel@tonic-gate
11497c478bd9Sstevel@tonic-gate ASSERT(domid != IDN_NIL_DOMID);
11507c478bd9Sstevel@tonic-gate
11517c478bd9Sstevel@tonic-gate wp = &idn.slabwaiter[domid];
11527c478bd9Sstevel@tonic-gate
11537c478bd9Sstevel@tonic-gate mutex_enter(&wp->w_mutex);
11547c478bd9Sstevel@tonic-gate
1155d3d50737SRafael Vanoni PR_SMR("%s: domain = %d, nwaiters = %d\n", proc, domid, wp->w_nwaiters);
11567c478bd9Sstevel@tonic-gate
11577c478bd9Sstevel@tonic-gate if (wp->w_nwaiters <= 0) {
11587c478bd9Sstevel@tonic-gate /*
11597c478bd9Sstevel@tonic-gate * Hmmm...nobody is registered!
11607c478bd9Sstevel@tonic-gate */
11617c478bd9Sstevel@tonic-gate PR_SMR("%s: NO WAITERS (domid = %d)\n", proc, domid);
11627c478bd9Sstevel@tonic-gate mutex_exit(&wp->w_mutex);
11637c478bd9Sstevel@tonic-gate return (EINVAL);
11647c478bd9Sstevel@tonic-gate }
11657c478bd9Sstevel@tonic-gate (wp->w_nwaiters)--;
11667c478bd9Sstevel@tonic-gate /*
11677c478bd9Sstevel@tonic-gate * Is our present under the tree?
11687c478bd9Sstevel@tonic-gate */
11697c478bd9Sstevel@tonic-gate if (!wp->w_done) {
11707c478bd9Sstevel@tonic-gate /*
11717c478bd9Sstevel@tonic-gate * Bummer...no presents. Let the caller know
11727c478bd9Sstevel@tonic-gate * via a null slab pointer.
11737c478bd9Sstevel@tonic-gate * Note that we don't clean up immediately since
11747c478bd9Sstevel@tonic-gate * message might still come in for other waiters.
11757c478bd9Sstevel@tonic-gate * Thus, late sleepers may still get a chance.
11767c478bd9Sstevel@tonic-gate */
11777c478bd9Sstevel@tonic-gate PR_SMR("%s: bummer no slab allocated for domain %d\n",
11787c478bd9Sstevel@tonic-gate proc, domid);
11797c478bd9Sstevel@tonic-gate ASSERT(wp->w_sp == NULL);
11807c478bd9Sstevel@tonic-gate (*spp) = NULL;
11817c478bd9Sstevel@tonic-gate serrno = wp->w_closed ? ECANCELED : EBUSY;
11827c478bd9Sstevel@tonic-gate
11837c478bd9Sstevel@tonic-gate } else {
11847c478bd9Sstevel@tonic-gate (*spp) = wp->w_sp;
11857c478bd9Sstevel@tonic-gate serrno = wp->w_serrno;
11867c478bd9Sstevel@tonic-gate
11877c478bd9Sstevel@tonic-gate #ifdef DEBUG
11887c478bd9Sstevel@tonic-gate if (serrno == 0) {
11897c478bd9Sstevel@tonic-gate register smr_slab_t *sp;
11907c478bd9Sstevel@tonic-gate
11917c478bd9Sstevel@tonic-gate ASSERT(wp->w_sp);
11927c478bd9Sstevel@tonic-gate PR_SMR("%s: allocation succeeded (domain %d)\n",
11937c478bd9Sstevel@tonic-gate proc, domid);
11947c478bd9Sstevel@tonic-gate
11957c478bd9Sstevel@tonic-gate DSLAB_LOCK_SHARED(domid);
11967c478bd9Sstevel@tonic-gate for (sp = idn_domain[domid].dslab; sp; sp = sp->sl_next)
11977c478bd9Sstevel@tonic-gate if (sp == wp->w_sp)
11987c478bd9Sstevel@tonic-gate break;
11997c478bd9Sstevel@tonic-gate if (sp == NULL)
12007c478bd9Sstevel@tonic-gate cmn_err(CE_WARN,
12017c478bd9Sstevel@tonic-gate "%s:%d: slab ptr = NULL",
12027c478bd9Sstevel@tonic-gate proc, domid);
12037c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(domid);
12047c478bd9Sstevel@tonic-gate } else {
12057c478bd9Sstevel@tonic-gate PR_SMR("%s: allocation failed (domain %d) "
12067c478bd9Sstevel@tonic-gate "[serrno = %d]\n", proc, domid, serrno);
12077c478bd9Sstevel@tonic-gate }
12087c478bd9Sstevel@tonic-gate #endif /* DEBUG */
12097c478bd9Sstevel@tonic-gate }
12107c478bd9Sstevel@tonic-gate if (wp->w_nwaiters == 0) {
12117c478bd9Sstevel@tonic-gate /*
12127c478bd9Sstevel@tonic-gate * Last one turns out the lights.
12137c478bd9Sstevel@tonic-gate */
12147c478bd9Sstevel@tonic-gate PR_SMR("%s: domain %d last waiter, turning out lights\n",
12157c478bd9Sstevel@tonic-gate proc, domid);
12167c478bd9Sstevel@tonic-gate wp->w_sp = NULL;
12177c478bd9Sstevel@tonic-gate wp->w_done = 0;
12187c478bd9Sstevel@tonic-gate wp->w_serrno = 0;
12197c478bd9Sstevel@tonic-gate }
12207c478bd9Sstevel@tonic-gate mutex_exit(&wp->w_mutex);
12217c478bd9Sstevel@tonic-gate
12227c478bd9Sstevel@tonic-gate return (serrno);
12237c478bd9Sstevel@tonic-gate }
12247c478bd9Sstevel@tonic-gate
12257c478bd9Sstevel@tonic-gate /*
12267c478bd9Sstevel@tonic-gate * Called to abort any slaballoc requests on behalf of the
12277c478bd9Sstevel@tonic-gate * given domain.
12287c478bd9Sstevel@tonic-gate */
12297c478bd9Sstevel@tonic-gate int
smr_slabwaiter_abort(int domid,int serrno)12307c478bd9Sstevel@tonic-gate smr_slabwaiter_abort(int domid, int serrno)
12317c478bd9Sstevel@tonic-gate {
12327c478bd9Sstevel@tonic-gate ASSERT(serrno != 0);
12337c478bd9Sstevel@tonic-gate
12347c478bd9Sstevel@tonic-gate return (smr_slaballoc_put(domid, NULL, 0, serrno));
12357c478bd9Sstevel@tonic-gate }
12367c478bd9Sstevel@tonic-gate
12377c478bd9Sstevel@tonic-gate /*
12387c478bd9Sstevel@tonic-gate * Put ourselves into a timedwait waiting for slab to be
12397c478bd9Sstevel@tonic-gate * allocated.
12407c478bd9Sstevel@tonic-gate * Returns with slaballoc mutex dropped.
12417c478bd9Sstevel@tonic-gate *
12427c478bd9Sstevel@tonic-gate * Returns: EINVAL
12437c478bd9Sstevel@tonic-gate * ETIMEDOUT
12447c478bd9Sstevel@tonic-gate * smr_slabwatier_unregister
12457c478bd9Sstevel@tonic-gate * (0, EINVAL, EBUSY, ENOMEM)
12467c478bd9Sstevel@tonic-gate */
12477c478bd9Sstevel@tonic-gate static int
smr_slaballoc_wait(int domid,smr_slab_t ** spp)12487c478bd9Sstevel@tonic-gate smr_slaballoc_wait(int domid, smr_slab_t **spp)
12497c478bd9Sstevel@tonic-gate {
12507c478bd9Sstevel@tonic-gate struct slabwaiter *wp;
12517c478bd9Sstevel@tonic-gate int serrno = 0, serrno_unreg;
12527c478bd9Sstevel@tonic-gate procname_t proc = "smr_slaballoc_wait";
12537c478bd9Sstevel@tonic-gate
12547c478bd9Sstevel@tonic-gate
12557c478bd9Sstevel@tonic-gate wp = &idn.slabwaiter[domid];
12567c478bd9Sstevel@tonic-gate
12577c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&wp->w_mutex));
12587c478bd9Sstevel@tonic-gate
12597c478bd9Sstevel@tonic-gate mutex_enter(&wp->w_mutex);
12607c478bd9Sstevel@tonic-gate
1261bf30efa4Smathue PR_SMR("%s: domain = %d, nwaiters = %d, wsp = 0x%p\n",
1262*07d06da5SSurya Prakki proc, domid, wp->w_nwaiters, (void *)wp->w_sp);
12637c478bd9Sstevel@tonic-gate
12647c478bd9Sstevel@tonic-gate if (wp->w_nwaiters <= 0) {
12657c478bd9Sstevel@tonic-gate /*
12667c478bd9Sstevel@tonic-gate * Hmmm...no waiters registered.
12677c478bd9Sstevel@tonic-gate */
1268d3d50737SRafael Vanoni PR_SMR("%s: domain %d, no waiters!\n", proc, domid);
12697c478bd9Sstevel@tonic-gate mutex_exit(&wp->w_mutex);
12707c478bd9Sstevel@tonic-gate return (EINVAL);
12717c478bd9Sstevel@tonic-gate }
12727c478bd9Sstevel@tonic-gate ASSERT(DSLAB_READ_HELD(domid));
12737c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(domid);
12747c478bd9Sstevel@tonic-gate
12757c478bd9Sstevel@tonic-gate if (!wp->w_done && !wp->w_closed) {
12767c478bd9Sstevel@tonic-gate int rv;
12777c478bd9Sstevel@tonic-gate
12787c478bd9Sstevel@tonic-gate /*
12797c478bd9Sstevel@tonic-gate * Only wait if data hasn't arrived yet.
12807c478bd9Sstevel@tonic-gate */
1281d3d50737SRafael Vanoni PR_SMR("%s: domain %d, going to sleep...\n", proc, domid);
12827c478bd9Sstevel@tonic-gate
1283d3d50737SRafael Vanoni rv = cv_reltimedwait_sig(&wp->w_cv, &wp->w_mutex,
1284d3d50737SRafael Vanoni IDN_SLABALLOC_WAITTIME, TR_CLOCK_TICK);
12857c478bd9Sstevel@tonic-gate if (rv == -1)
12867c478bd9Sstevel@tonic-gate serrno = ETIMEDOUT;
12877c478bd9Sstevel@tonic-gate
12887c478bd9Sstevel@tonic-gate PR_SMR("%s: domain %d, awakened (reason = %s)\n",
12897c478bd9Sstevel@tonic-gate proc, domid, (rv == -1) ? "TIMEOUT" : "SIGNALED");
12907c478bd9Sstevel@tonic-gate }
12917c478bd9Sstevel@tonic-gate /*
12927c478bd9Sstevel@tonic-gate * We've awakened or request already filled!
12937c478bd9Sstevel@tonic-gate * Unregister ourselves.
12947c478bd9Sstevel@tonic-gate */
12957c478bd9Sstevel@tonic-gate mutex_exit(&wp->w_mutex);
12967c478bd9Sstevel@tonic-gate
12977c478bd9Sstevel@tonic-gate /*
12987c478bd9Sstevel@tonic-gate * Any gifts will be entered into spp.
12997c478bd9Sstevel@tonic-gate */
13007c478bd9Sstevel@tonic-gate serrno_unreg = smr_slabwaiter_unregister(domid, spp);
13017c478bd9Sstevel@tonic-gate
13027c478bd9Sstevel@tonic-gate /*
13037c478bd9Sstevel@tonic-gate * Leave with reader lock on dslab_lock.
13047c478bd9Sstevel@tonic-gate */
13057c478bd9Sstevel@tonic-gate DSLAB_LOCK_SHARED(domid);
13067c478bd9Sstevel@tonic-gate
13077c478bd9Sstevel@tonic-gate if ((serrno_unreg == EBUSY) && (serrno == ETIMEDOUT))
13087c478bd9Sstevel@tonic-gate return (serrno);
13097c478bd9Sstevel@tonic-gate else
13107c478bd9Sstevel@tonic-gate return (serrno_unreg);
13117c478bd9Sstevel@tonic-gate }
13127c478bd9Sstevel@tonic-gate
13137c478bd9Sstevel@tonic-gate /*
13147c478bd9Sstevel@tonic-gate * A SMR slab was allocated on behalf of the given domain.
13157c478bd9Sstevel@tonic-gate * Wakeup anybody that may have been waiting for the allocation.
13167c478bd9Sstevel@tonic-gate * Note that if the domain is a remote one, i.e. master is allocating
13177c478bd9Sstevel@tonic-gate * on behalf of a slave, it's up to the caller to transmit the
13187c478bd9Sstevel@tonic-gate * allocation response to that domain.
13197c478bd9Sstevel@tonic-gate * The force flag indicates that we want to install the slab for
13207c478bd9Sstevel@tonic-gate * the given user regardless of whether there are waiters or not.
13217c478bd9Sstevel@tonic-gate * This is used primarily in situations where a slave may have timed
13227c478bd9Sstevel@tonic-gate * out before the response actually arrived. In this situation we
13237c478bd9Sstevel@tonic-gate * don't want to send slab back to the master after we went through
13247c478bd9Sstevel@tonic-gate * the trouble of allocating one. Master is _not_ allowed to do this
13257c478bd9Sstevel@tonic-gate * for remote domains.
13267c478bd9Sstevel@tonic-gate *
13277c478bd9Sstevel@tonic-gate * Returns: -1 Non-registered waiter or waiting area garbaged.
13287c478bd9Sstevel@tonic-gate * 0 Successfully performed operation.
13297c478bd9Sstevel@tonic-gate */
13307c478bd9Sstevel@tonic-gate int
smr_slaballoc_put(int domid,smr_slab_t * sp,int forceflag,int serrno)13317c478bd9Sstevel@tonic-gate smr_slaballoc_put(int domid, smr_slab_t *sp, int forceflag, int serrno)
13327c478bd9Sstevel@tonic-gate {
13337c478bd9Sstevel@tonic-gate idn_domain_t *dp;
13347c478bd9Sstevel@tonic-gate struct slabwaiter *wp;
13357c478bd9Sstevel@tonic-gate procname_t proc = "smr_slaballoc_put";
13367c478bd9Sstevel@tonic-gate
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate dp = &idn_domain[domid];
13397c478bd9Sstevel@tonic-gate
13407c478bd9Sstevel@tonic-gate ASSERT(!serrno ? DSLAB_WRITE_HELD(domid) : 1);
13417c478bd9Sstevel@tonic-gate
13427c478bd9Sstevel@tonic-gate if (domid == IDN_NIL_DOMID)
13437c478bd9Sstevel@tonic-gate return (-1);
13447c478bd9Sstevel@tonic-gate
13457c478bd9Sstevel@tonic-gate ASSERT(serrno ? (sp == NULL) : (sp != NULL));
13467c478bd9Sstevel@tonic-gate
13477c478bd9Sstevel@tonic-gate wp = &idn.slabwaiter[domid];
13487c478bd9Sstevel@tonic-gate
13497c478bd9Sstevel@tonic-gate mutex_enter(&wp->w_mutex);
13507c478bd9Sstevel@tonic-gate
1351bf30efa4Smathue PR_SMR("%s: domain = %d, bufp = 0x%p, ebufp = 0x%p, "
1352bf30efa4Smathue "(f = %d, se = %d)\n", proc, domid,
1353*07d06da5SSurya Prakki (sp ? (void *)sp->sl_start : 0),
1354*07d06da5SSurya Prakki (sp ? (void *)sp->sl_end : 0), forceflag, serrno);
13557c478bd9Sstevel@tonic-gate
13567c478bd9Sstevel@tonic-gate if (wp->w_nwaiters <= 0) {
13577c478bd9Sstevel@tonic-gate /*
13587c478bd9Sstevel@tonic-gate * There are no waiters!! Must have timed out
13597c478bd9Sstevel@tonic-gate * and left. Oh well...
13607c478bd9Sstevel@tonic-gate */
13617c478bd9Sstevel@tonic-gate PR_SMR("%s: no slaballoc waiters found for domain %d\n",
13627c478bd9Sstevel@tonic-gate proc, domid);
13637c478bd9Sstevel@tonic-gate if (!forceflag || serrno || !sp) {
13647c478bd9Sstevel@tonic-gate /*
13657c478bd9Sstevel@tonic-gate * No waiters and caller doesn't want to force it.
13667c478bd9Sstevel@tonic-gate */
13677c478bd9Sstevel@tonic-gate mutex_exit(&wp->w_mutex);
13687c478bd9Sstevel@tonic-gate return (-1);
13697c478bd9Sstevel@tonic-gate }
13707c478bd9Sstevel@tonic-gate PR_SMR("%s: forcing slab onto domain %d\n", proc, domid);
13717c478bd9Sstevel@tonic-gate ASSERT(domid == idn.localid);
13727c478bd9Sstevel@tonic-gate ASSERT(wp->w_sp == NULL);
13737c478bd9Sstevel@tonic-gate wp->w_done = 0;
13747c478bd9Sstevel@tonic-gate /*
13757c478bd9Sstevel@tonic-gate * Now we fall through and let it be added in the
13767c478bd9Sstevel@tonic-gate * regular manor.
13777c478bd9Sstevel@tonic-gate */
13787c478bd9Sstevel@tonic-gate }
13797c478bd9Sstevel@tonic-gate if (wp->w_done) {
13807c478bd9Sstevel@tonic-gate /*
13817c478bd9Sstevel@tonic-gate * There's at least one waiter so there has
13827c478bd9Sstevel@tonic-gate * to be a slab structure waiting for us.
13837c478bd9Sstevel@tonic-gate * If everything is going smoothly, there should only
13847c478bd9Sstevel@tonic-gate * be one guy coming through the path of inserting
13857c478bd9Sstevel@tonic-gate * an error or good slab. However, if a disconnect was
13867c478bd9Sstevel@tonic-gate * detected, you may get several guys coming through
13877c478bd9Sstevel@tonic-gate * trying to let everybody know.
13887c478bd9Sstevel@tonic-gate */
13897c478bd9Sstevel@tonic-gate ASSERT(wp->w_serrno ?
13907c478bd9Sstevel@tonic-gate (wp->w_sp == NULL) : (wp->w_sp != NULL));
13917c478bd9Sstevel@tonic-gate
13927c478bd9Sstevel@tonic-gate cv_broadcast(&wp->w_cv);
13937c478bd9Sstevel@tonic-gate mutex_exit(&wp->w_mutex);
13947c478bd9Sstevel@tonic-gate
13957c478bd9Sstevel@tonic-gate return (-1);
13967c478bd9Sstevel@tonic-gate }
13977c478bd9Sstevel@tonic-gate if (serrno != 0) {
13987c478bd9Sstevel@tonic-gate /*
13997c478bd9Sstevel@tonic-gate * Bummer...allocation failed. This call is simply
14007c478bd9Sstevel@tonic-gate * to wake up the sleepers and let them know.
14017c478bd9Sstevel@tonic-gate */
1402d3d50737SRafael Vanoni PR_SMR("%s: slaballoc failed for domain %d\n", proc, domid);
14037c478bd9Sstevel@tonic-gate wp->w_serrno = serrno;
14047c478bd9Sstevel@tonic-gate wp->w_done = 1;
14057c478bd9Sstevel@tonic-gate cv_broadcast(&wp->w_cv);
14067c478bd9Sstevel@tonic-gate mutex_exit(&wp->w_mutex);
14077c478bd9Sstevel@tonic-gate
14087c478bd9Sstevel@tonic-gate return (0);
14097c478bd9Sstevel@tonic-gate }
14107c478bd9Sstevel@tonic-gate PR_SMR("%s: putting slab into struct (domid=%d, localid=%d)\n",
14117c478bd9Sstevel@tonic-gate proc, domid, idn.localid);
14127c478bd9Sstevel@tonic-gate /*
14137c478bd9Sstevel@tonic-gate * Prep the slab structure.
14147c478bd9Sstevel@tonic-gate */
14157c478bd9Sstevel@tonic-gate
14167c478bd9Sstevel@tonic-gate if (domid == idn.localid) {
14177c478bd9Sstevel@tonic-gate /*
14187c478bd9Sstevel@tonic-gate * Allocation was indeed for me.
14197c478bd9Sstevel@tonic-gate * Slab may or may not be locked when
14207c478bd9Sstevel@tonic-gate * we reach. Normally they will be locked
14217c478bd9Sstevel@tonic-gate * if we're being called on behalf of a
14227c478bd9Sstevel@tonic-gate * free, and not locked if on behalf of
14237c478bd9Sstevel@tonic-gate * a new allocation request.
14247c478bd9Sstevel@tonic-gate */
14257c478bd9Sstevel@tonic-gate lock_clear(&sp->sl_lock);
14267c478bd9Sstevel@tonic-gate smr_alloc_buflist(sp);
14277c478bd9Sstevel@tonic-gate #ifdef DEBUG
14287c478bd9Sstevel@tonic-gate } else {
14297c478bd9Sstevel@tonic-gate uint_t rv;
14307c478bd9Sstevel@tonic-gate /*
14317c478bd9Sstevel@tonic-gate * Slab was not allocated on my behalf. Must be
14327c478bd9Sstevel@tonic-gate * a master request on behalf of some other domain.
14337c478bd9Sstevel@tonic-gate * Prep appropriately. Slab should have been locked
14347c478bd9Sstevel@tonic-gate * by smr_slab_reserve.
14357c478bd9Sstevel@tonic-gate */
14367c478bd9Sstevel@tonic-gate rv = lock_try(&sp->sl_lock);
14377c478bd9Sstevel@tonic-gate ASSERT(!rv);
14387c478bd9Sstevel@tonic-gate ASSERT(sp->sl_domid == (short)domid);
14397c478bd9Sstevel@tonic-gate #endif /* DEBUG */
14407c478bd9Sstevel@tonic-gate }
14417c478bd9Sstevel@tonic-gate
14427c478bd9Sstevel@tonic-gate /*
14437c478bd9Sstevel@tonic-gate * Slab is ready to go. Insert it into the domain's
14447c478bd9Sstevel@tonic-gate * slab list so once we wake everybody up they'll find it.
14457c478bd9Sstevel@tonic-gate * You better have write lock if you're putting treasures
14467c478bd9Sstevel@tonic-gate * there.
14477c478bd9Sstevel@tonic-gate */
14487c478bd9Sstevel@tonic-gate ASSERT(DSLAB_WRITE_HELD(domid));
14497c478bd9Sstevel@tonic-gate
14507c478bd9Sstevel@tonic-gate sp->sl_next = dp->dslab;
14517c478bd9Sstevel@tonic-gate dp->dslab = sp;
14527c478bd9Sstevel@tonic-gate dp->dnslabs++;
14537c478bd9Sstevel@tonic-gate
14547c478bd9Sstevel@tonic-gate /*
14557c478bd9Sstevel@tonic-gate * It's possible to fall through here without waiters.
14567c478bd9Sstevel@tonic-gate * This is a case where forceflag was set.
14577c478bd9Sstevel@tonic-gate */
14587c478bd9Sstevel@tonic-gate if (wp->w_nwaiters > 0) {
14597c478bd9Sstevel@tonic-gate wp->w_sp = sp;
14607c478bd9Sstevel@tonic-gate wp->w_serrno = serrno;
14617c478bd9Sstevel@tonic-gate wp->w_done = 1;
14627c478bd9Sstevel@tonic-gate cv_broadcast(&wp->w_cv);
14637c478bd9Sstevel@tonic-gate } else {
14647c478bd9Sstevel@tonic-gate ASSERT(forceflag);
14657c478bd9Sstevel@tonic-gate wp->w_sp = NULL;
14667c478bd9Sstevel@tonic-gate wp->w_serrno = 0;
14677c478bd9Sstevel@tonic-gate wp->w_done = 0;
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate mutex_exit(&wp->w_mutex);
14707c478bd9Sstevel@tonic-gate
14717c478bd9Sstevel@tonic-gate return (0);
14727c478bd9Sstevel@tonic-gate }
14737c478bd9Sstevel@tonic-gate
14747c478bd9Sstevel@tonic-gate /*
14757c478bd9Sstevel@tonic-gate * Get the slab representing [bufp,ebufp] from the respective
14767c478bd9Sstevel@tonic-gate * domain's pool if all the buffers are free. Remove them from
14777c478bd9Sstevel@tonic-gate * the domain's list and return it.
14787c478bd9Sstevel@tonic-gate * If bufp == NULL, then return however many free ones you
14797c478bd9Sstevel@tonic-gate * can find.
14807c478bd9Sstevel@tonic-gate * List of slabs are returned locked (sl_lock).
14817c478bd9Sstevel@tonic-gate * XXX - Need minimum limit to make sure we don't free up _all_
14827c478bd9Sstevel@tonic-gate * of our slabs! However, during a shutdown we will need
14837c478bd9Sstevel@tonic-gate * method to free them all up regardless of locking.
14847c478bd9Sstevel@tonic-gate */
14857c478bd9Sstevel@tonic-gate smr_slab_t *
smr_slaballoc_get(int domid,caddr_t bufp,caddr_t ebufp)14867c478bd9Sstevel@tonic-gate smr_slaballoc_get(int domid, caddr_t bufp, caddr_t ebufp)
14877c478bd9Sstevel@tonic-gate {
14887c478bd9Sstevel@tonic-gate idn_domain_t *dp;
14897c478bd9Sstevel@tonic-gate smr_slab_t *retsp, *sp, **psp;
14907c478bd9Sstevel@tonic-gate int foundit, islocal = 0;
14917c478bd9Sstevel@tonic-gate int nslabs;
14927c478bd9Sstevel@tonic-gate procname_t proc = "smr_slaballoc_get";
14937c478bd9Sstevel@tonic-gate
1494bf30efa4Smathue PR_SMR("%s: getting slab for domain %d [bufp=0x%p, ebufp=0x%p]\n",
1495*07d06da5SSurya Prakki proc, domid, (void *)bufp, (void *)ebufp);
14967c478bd9Sstevel@tonic-gate
14977c478bd9Sstevel@tonic-gate dp = &idn_domain[domid];
14987c478bd9Sstevel@tonic-gate
14997c478bd9Sstevel@tonic-gate ASSERT(DSLAB_WRITE_HELD(domid));
15007c478bd9Sstevel@tonic-gate
15017c478bd9Sstevel@tonic-gate if ((sp = dp->dslab) == NULL) {
1502d3d50737SRafael Vanoni PR_SMR("%s: oops, no slabs for domain %d\n", proc, domid);
15037c478bd9Sstevel@tonic-gate return (NULL);
15047c478bd9Sstevel@tonic-gate }
15057c478bd9Sstevel@tonic-gate /*
15067c478bd9Sstevel@tonic-gate * If domid is myself then I'm trying to get a slab out
15077c478bd9Sstevel@tonic-gate * of my local pool. Otherwise, I'm the master and
15087c478bd9Sstevel@tonic-gate * I'm trying to get the slab representative from the
15097c478bd9Sstevel@tonic-gate * global pool.
15107c478bd9Sstevel@tonic-gate */
15117c478bd9Sstevel@tonic-gate if (domid == idn.localid)
15127c478bd9Sstevel@tonic-gate islocal = 1;
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate if (bufp != NULL) {
15157c478bd9Sstevel@tonic-gate nslabs = -1;
15167c478bd9Sstevel@tonic-gate } else {
15177c478bd9Sstevel@tonic-gate nslabs = *(int *)ebufp;
15187c478bd9Sstevel@tonic-gate if (nslabs == 0) {
15197c478bd9Sstevel@tonic-gate PR_SMR("%s: requested nslabs (%d) <= 0\n",
15207c478bd9Sstevel@tonic-gate proc, nslabs);
15217c478bd9Sstevel@tonic-gate return (NULL);
15227c478bd9Sstevel@tonic-gate } else if (nslabs < 0) {
15237c478bd9Sstevel@tonic-gate /*
15247c478bd9Sstevel@tonic-gate * Caller wants them all!
15257c478bd9Sstevel@tonic-gate */
15267c478bd9Sstevel@tonic-gate nslabs = (int)dp->dnslabs;
15277c478bd9Sstevel@tonic-gate }
15287c478bd9Sstevel@tonic-gate }
15297c478bd9Sstevel@tonic-gate
15307c478bd9Sstevel@tonic-gate retsp = NULL;
15317c478bd9Sstevel@tonic-gate foundit = 0;
15327c478bd9Sstevel@tonic-gate for (psp = &dp->dslab; sp; sp = *psp) {
15337c478bd9Sstevel@tonic-gate int isbusy;
15347c478bd9Sstevel@tonic-gate
15357c478bd9Sstevel@tonic-gate if (bufp && (sp->sl_start != bufp)) {
15367c478bd9Sstevel@tonic-gate psp = &sp->sl_next;
15377c478bd9Sstevel@tonic-gate continue;
15387c478bd9Sstevel@tonic-gate }
15397c478bd9Sstevel@tonic-gate
15407c478bd9Sstevel@tonic-gate if (bufp && (ebufp > sp->sl_end)) {
1541bf30efa4Smathue PR_SMR("%s: bufp/ebufp (0x%p/0x%p) "
1542*07d06da5SSurya Prakki "expected (0x%p/0x%p)\n", proc, (void *)bufp,
1543*07d06da5SSurya Prakki (void *)ebufp, (void *)sp->sl_start,
1544*07d06da5SSurya Prakki (void *)sp->sl_end);
15457c478bd9Sstevel@tonic-gate ASSERT(0);
15467c478bd9Sstevel@tonic-gate }
15477c478bd9Sstevel@tonic-gate /*
15487c478bd9Sstevel@tonic-gate * We found the desired slab. Make sure
15497c478bd9Sstevel@tonic-gate * it's free.
15507c478bd9Sstevel@tonic-gate */
15517c478bd9Sstevel@tonic-gate foundit++;
15527c478bd9Sstevel@tonic-gate isbusy = 0;
15537c478bd9Sstevel@tonic-gate if (islocal) {
15547c478bd9Sstevel@tonic-gate int spl;
15557c478bd9Sstevel@tonic-gate
15567c478bd9Sstevel@tonic-gate /*
15577c478bd9Sstevel@tonic-gate * Some of the buffers in the slab
15587c478bd9Sstevel@tonic-gate * are still in use. Unlock the
15597c478bd9Sstevel@tonic-gate * buffers we locked and bail out.
15607c478bd9Sstevel@tonic-gate */
15617c478bd9Sstevel@tonic-gate spl = splhi();
15627c478bd9Sstevel@tonic-gate if (!lock_try(&sp->sl_lock)) {
15637c478bd9Sstevel@tonic-gate isbusy = 1;
15647c478bd9Sstevel@tonic-gate foundit--;
15657c478bd9Sstevel@tonic-gate } else if (sp->sl_inuse) {
15667c478bd9Sstevel@tonic-gate lock_clear(&sp->sl_lock);
15677c478bd9Sstevel@tonic-gate isbusy = 1;
15687c478bd9Sstevel@tonic-gate foundit--;
15697c478bd9Sstevel@tonic-gate }
15707c478bd9Sstevel@tonic-gate splx(spl);
15717c478bd9Sstevel@tonic-gate } else {
15727c478bd9Sstevel@tonic-gate /*
15737c478bd9Sstevel@tonic-gate * If not local, then I'm the master getting
15747c478bd9Sstevel@tonic-gate * a slab from one of the slaves. In this case,
15757c478bd9Sstevel@tonic-gate * their slab structs will always be locked.
15767c478bd9Sstevel@tonic-gate */
15777c478bd9Sstevel@tonic-gate ASSERT(!lock_try(&sp->sl_lock));
15787c478bd9Sstevel@tonic-gate }
15797c478bd9Sstevel@tonic-gate if (!isbusy) {
15807c478bd9Sstevel@tonic-gate /*
15817c478bd9Sstevel@tonic-gate * Delete the entry from the list and slap
15827c478bd9Sstevel@tonic-gate * it onto our return list.
15837c478bd9Sstevel@tonic-gate */
15847c478bd9Sstevel@tonic-gate *psp = sp->sl_next;
15857c478bd9Sstevel@tonic-gate sp->sl_next = retsp;
15867c478bd9Sstevel@tonic-gate retsp = sp;
15877c478bd9Sstevel@tonic-gate } else {
15887c478bd9Sstevel@tonic-gate psp = &sp->sl_next;
15897c478bd9Sstevel@tonic-gate }
15907c478bd9Sstevel@tonic-gate /*
15917c478bd9Sstevel@tonic-gate * If bufp == NULL (alternate interface) and we haven't
15927c478bd9Sstevel@tonic-gate * found the desired number of slabs yet, keep looking.
15937c478bd9Sstevel@tonic-gate */
15947c478bd9Sstevel@tonic-gate if (bufp || (foundit == nslabs))
15957c478bd9Sstevel@tonic-gate break;
15967c478bd9Sstevel@tonic-gate }
15977c478bd9Sstevel@tonic-gate dp->dnslabs -= (short)foundit;
15987c478bd9Sstevel@tonic-gate
15997c478bd9Sstevel@tonic-gate if (foundit) {
1600d3d50737SRafael Vanoni PR_SMR("%s: found %d free slabs (domid = %d)\n", proc, foundit,
1601d3d50737SRafael Vanoni domid);
16027c478bd9Sstevel@tonic-gate } else {
1603d3d50737SRafael Vanoni PR_SMR("%s: no free slabs found (domid = %d)\n", proc, domid);
16047c478bd9Sstevel@tonic-gate }
16057c478bd9Sstevel@tonic-gate
16067c478bd9Sstevel@tonic-gate /*
16077c478bd9Sstevel@tonic-gate * If this is the alternate interface, need to return
16087c478bd9Sstevel@tonic-gate * the number of slabs found in the ebufp parameter.
16097c478bd9Sstevel@tonic-gate */
16107c478bd9Sstevel@tonic-gate if (bufp == NULL)
16117c478bd9Sstevel@tonic-gate *(int *)ebufp = foundit;
16127c478bd9Sstevel@tonic-gate
16137c478bd9Sstevel@tonic-gate return (retsp);
16147c478bd9Sstevel@tonic-gate }
16157c478bd9Sstevel@tonic-gate
16167c478bd9Sstevel@tonic-gate /*
16177c478bd9Sstevel@tonic-gate * Wrapper to hide alternate interface to smr_slaballoc_get()
16187c478bd9Sstevel@tonic-gate */
16197c478bd9Sstevel@tonic-gate smr_slab_t *
smr_slaballoc_get_n(int domid,int * nslabs)16207c478bd9Sstevel@tonic-gate smr_slaballoc_get_n(int domid, int *nslabs)
16217c478bd9Sstevel@tonic-gate {
16227c478bd9Sstevel@tonic-gate smr_slab_t *sp;
16237c478bd9Sstevel@tonic-gate
16247c478bd9Sstevel@tonic-gate ASSERT(DSLAB_WRITE_HELD(domid));
16257c478bd9Sstevel@tonic-gate
16267c478bd9Sstevel@tonic-gate sp = smr_slaballoc_get(domid, NULL, (caddr_t)nslabs);
16277c478bd9Sstevel@tonic-gate
16287c478bd9Sstevel@tonic-gate return (sp);
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate
16317c478bd9Sstevel@tonic-gate /*
16327c478bd9Sstevel@tonic-gate * Only called by master. Initialize slab pool based on local SMR.
16337c478bd9Sstevel@tonic-gate * Returns number of slabs initialized.
16347c478bd9Sstevel@tonic-gate * reserved_size = Length of area at the front of the NWR portion
16357c478bd9Sstevel@tonic-gate * of the SMR to reserve and not make available for
16367c478bd9Sstevel@tonic-gate * slab allocations. Must be a IDN_SMR_BUFSIZE multiple.
16377c478bd9Sstevel@tonic-gate * reserved_area = Pointer to reserved area, if any.
16387c478bd9Sstevel@tonic-gate */
16397c478bd9Sstevel@tonic-gate int
smr_slabpool_init(size_t reserved_size,caddr_t * reserved_area)16407c478bd9Sstevel@tonic-gate smr_slabpool_init(size_t reserved_size, caddr_t *reserved_area)
16417c478bd9Sstevel@tonic-gate {
16427c478bd9Sstevel@tonic-gate size_t nwr_available;
16437c478bd9Sstevel@tonic-gate int minperpool, ntotslabs, nxslabs, nslabs;
16447c478bd9Sstevel@tonic-gate register int p, pp;
16457c478bd9Sstevel@tonic-gate register caddr_t bufp;
16467c478bd9Sstevel@tonic-gate register smr_slab_t *sp;
16477c478bd9Sstevel@tonic-gate
16487c478bd9Sstevel@tonic-gate ASSERT(IDN_GLOCK_IS_EXCL());
16497c478bd9Sstevel@tonic-gate ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
16507c478bd9Sstevel@tonic-gate
16517c478bd9Sstevel@tonic-gate *reserved_area = NULL;
16527c478bd9Sstevel@tonic-gate
16537c478bd9Sstevel@tonic-gate nwr_available = MB2B(IDN_NWR_SIZE) - reserved_size;
16547c478bd9Sstevel@tonic-gate
16557c478bd9Sstevel@tonic-gate if ((idn.localid != IDN_GET_MASTERID()) ||
16567c478bd9Sstevel@tonic-gate (nwr_available < IDN_SLAB_SIZE) ||
16577c478bd9Sstevel@tonic-gate (idn.slabpool != NULL) ||
16587c478bd9Sstevel@tonic-gate ((reserved_size != 0) && (reserved_size & (IDN_SMR_BUFSIZE-1)))) {
16597c478bd9Sstevel@tonic-gate return (-1);
16607c478bd9Sstevel@tonic-gate }
16617c478bd9Sstevel@tonic-gate
16627c478bd9Sstevel@tonic-gate idn.slabpool = GETSTRUCT(struct slabpool, 1);
16637c478bd9Sstevel@tonic-gate idn.slabpool->ntotslabs = ntotslabs = nwr_available / IDN_SLAB_SIZE;
16647c478bd9Sstevel@tonic-gate ASSERT(ntotslabs > 0);
16657c478bd9Sstevel@tonic-gate minperpool = (ntotslabs < IDN_SLAB_MINPERPOOL) ?
16667c478bd9Sstevel@tonic-gate 1 : IDN_SLAB_MINPERPOOL;
16677c478bd9Sstevel@tonic-gate idn.slabpool->npools = (ntotslabs + (minperpool - 1)) / minperpool;
16687c478bd9Sstevel@tonic-gate
16697c478bd9Sstevel@tonic-gate if ((idn.slabpool->npools & 1) == 0) {
16707c478bd9Sstevel@tonic-gate /*
16717c478bd9Sstevel@tonic-gate * npools needs to be odd for hashing algorithm.
16727c478bd9Sstevel@tonic-gate */
16737c478bd9Sstevel@tonic-gate idn.slabpool->npools++;
16747c478bd9Sstevel@tonic-gate }
16757c478bd9Sstevel@tonic-gate ASSERT(idn.slabpool->npools > 0);
16767c478bd9Sstevel@tonic-gate minperpool = (ntotslabs < idn.slabpool->npools) ?
16777c478bd9Sstevel@tonic-gate 1 : (ntotslabs / idn.slabpool->npools);
16787c478bd9Sstevel@tonic-gate
16797c478bd9Sstevel@tonic-gate /*
16807c478bd9Sstevel@tonic-gate * Calculate the number of extra slabs that will need to
16817c478bd9Sstevel@tonic-gate * be alloted to the pools. This number will be less than
16827c478bd9Sstevel@tonic-gate * npools. Only one extra slab is allocated to each pool
16837c478bd9Sstevel@tonic-gate * until we have assigned all the extra slabs.
16847c478bd9Sstevel@tonic-gate */
16857c478bd9Sstevel@tonic-gate if (ntotslabs > (idn.slabpool->npools * minperpool))
16867c478bd9Sstevel@tonic-gate nxslabs = ntotslabs - (idn.slabpool->npools * minperpool);
16877c478bd9Sstevel@tonic-gate else
16887c478bd9Sstevel@tonic-gate nxslabs = 0;
16897c478bd9Sstevel@tonic-gate ASSERT((nxslabs >= 0) && (nxslabs < idn.slabpool->npools));
16907c478bd9Sstevel@tonic-gate
16917c478bd9Sstevel@tonic-gate idn.slabpool->pool = GETSTRUCT(struct smr_slabtbl,
16927c478bd9Sstevel@tonic-gate idn.slabpool->npools);
16937c478bd9Sstevel@tonic-gate sp = GETSTRUCT(smr_slab_t, idn.slabpool->ntotslabs);
16947c478bd9Sstevel@tonic-gate
16957c478bd9Sstevel@tonic-gate idn.slabpool->savep = sp;
16967c478bd9Sstevel@tonic-gate bufp = idn.smr.vaddr + reserved_size;
16977c478bd9Sstevel@tonic-gate
16987c478bd9Sstevel@tonic-gate for (p = nslabs = 0;
16997c478bd9Sstevel@tonic-gate (p < idn.slabpool->npools) && (ntotslabs > 0);
17007c478bd9Sstevel@tonic-gate p++, ntotslabs -= nslabs) {
17017c478bd9Sstevel@tonic-gate
17027c478bd9Sstevel@tonic-gate nslabs = (ntotslabs < minperpool) ? ntotslabs : minperpool;
17037c478bd9Sstevel@tonic-gate if (nxslabs > 0) {
17047c478bd9Sstevel@tonic-gate nslabs++;
17057c478bd9Sstevel@tonic-gate nxslabs--;
17067c478bd9Sstevel@tonic-gate }
17077c478bd9Sstevel@tonic-gate idn.slabpool->pool[p].sarray = sp;
17087c478bd9Sstevel@tonic-gate for (pp = 0; pp < nslabs; pp++) {
17097c478bd9Sstevel@tonic-gate
17107c478bd9Sstevel@tonic-gate sp->sl_next = NULL;
17117c478bd9Sstevel@tonic-gate sp->sl_start = bufp;
17127c478bd9Sstevel@tonic-gate sp->sl_end = bufp = sp->sl_start + IDN_SLAB_SIZE;
17137c478bd9Sstevel@tonic-gate sp->sl_lock = 0;
17147c478bd9Sstevel@tonic-gate sp->sl_domid = (short)IDN_NIL_DOMID;
17157c478bd9Sstevel@tonic-gate
17167c478bd9Sstevel@tonic-gate sp++;
17177c478bd9Sstevel@tonic-gate }
17187c478bd9Sstevel@tonic-gate idn.slabpool->pool[p].nfree = nslabs;
17197c478bd9Sstevel@tonic-gate idn.slabpool->pool[p].nslabs = nslabs;
17207c478bd9Sstevel@tonic-gate }
17217c478bd9Sstevel@tonic-gate ASSERT((ntotslabs == 0) && (nxslabs == 0));
17227c478bd9Sstevel@tonic-gate /*
17237c478bd9Sstevel@tonic-gate * We should be at the end of the SMR at this point.
17247c478bd9Sstevel@tonic-gate */
1725d3d50737SRafael Vanoni ASSERT(bufp == (idn.smr.vaddr + reserved_size
17267c478bd9Sstevel@tonic-gate + (idn.slabpool->ntotslabs * IDN_SLAB_SIZE)));
17277c478bd9Sstevel@tonic-gate
17287c478bd9Sstevel@tonic-gate if (reserved_size != 0)
17297c478bd9Sstevel@tonic-gate *reserved_area = idn.smr.vaddr;
17307c478bd9Sstevel@tonic-gate
17317c478bd9Sstevel@tonic-gate return (0);
17327c478bd9Sstevel@tonic-gate }
17337c478bd9Sstevel@tonic-gate
17347c478bd9Sstevel@tonic-gate void
smr_slabpool_deinit()17357c478bd9Sstevel@tonic-gate smr_slabpool_deinit()
17367c478bd9Sstevel@tonic-gate {
17377c478bd9Sstevel@tonic-gate if (idn.slabpool == NULL)
17387c478bd9Sstevel@tonic-gate return;
17397c478bd9Sstevel@tonic-gate
17407c478bd9Sstevel@tonic-gate FREESTRUCT(idn.slabpool->savep, smr_slab_t, idn.slabpool->ntotslabs);
17417c478bd9Sstevel@tonic-gate FREESTRUCT(idn.slabpool->pool, struct smr_slabtbl,
17427c478bd9Sstevel@tonic-gate idn.slabpool->npools);
17437c478bd9Sstevel@tonic-gate FREESTRUCT(idn.slabpool, struct slabpool, 1);
17447c478bd9Sstevel@tonic-gate
17457c478bd9Sstevel@tonic-gate idn.slabpool = NULL;
17467c478bd9Sstevel@tonic-gate }
17477c478bd9Sstevel@tonic-gate
17487c478bd9Sstevel@tonic-gate void
smr_alloc_buflist(smr_slab_t * sp)17497c478bd9Sstevel@tonic-gate smr_alloc_buflist(smr_slab_t *sp)
17507c478bd9Sstevel@tonic-gate {
17517c478bd9Sstevel@tonic-gate int n, nbufs;
17527c478bd9Sstevel@tonic-gate caddr_t sbufp;
17537c478bd9Sstevel@tonic-gate smr_slabbuf_t *hp, *bp;
17547c478bd9Sstevel@tonic-gate
17557c478bd9Sstevel@tonic-gate if (sp->sl_head)
17567c478bd9Sstevel@tonic-gate return;
17577c478bd9Sstevel@tonic-gate
17587c478bd9Sstevel@tonic-gate nbufs = (sp->sl_end - sp->sl_start) / IDN_SMR_BUFSIZE;
17597c478bd9Sstevel@tonic-gate ASSERT(nbufs > 0);
17607c478bd9Sstevel@tonic-gate if (nbufs <= 0) {
17617c478bd9Sstevel@tonic-gate sp->sl_head = sp->sl_free = sp->sl_inuse = NULL;
17627c478bd9Sstevel@tonic-gate return;
17637c478bd9Sstevel@tonic-gate }
17647c478bd9Sstevel@tonic-gate
17657c478bd9Sstevel@tonic-gate hp = GETSTRUCT(smr_slabbuf_t, nbufs);
17667c478bd9Sstevel@tonic-gate
17677c478bd9Sstevel@tonic-gate sbufp = sp->sl_start;
17687c478bd9Sstevel@tonic-gate for (n = 0, bp = hp; n < nbufs; bp++, n++) {
17697c478bd9Sstevel@tonic-gate bp->sb_bufp = sbufp;
17707c478bd9Sstevel@tonic-gate bp->sb_domid = IDN_NIL_DOMID;
17717c478bd9Sstevel@tonic-gate bp->sb_next = bp + 1;
17727c478bd9Sstevel@tonic-gate sbufp += IDN_SMR_BUFSIZE;
17737c478bd9Sstevel@tonic-gate }
17747c478bd9Sstevel@tonic-gate (--bp)->sb_next = NULL;
17757c478bd9Sstevel@tonic-gate
17767c478bd9Sstevel@tonic-gate sp->sl_head = sp->sl_free = hp;
17777c478bd9Sstevel@tonic-gate sp->sl_inuse = NULL;
17787c478bd9Sstevel@tonic-gate }
17797c478bd9Sstevel@tonic-gate
17807c478bd9Sstevel@tonic-gate void
smr_free_buflist(smr_slab_t * sp)17817c478bd9Sstevel@tonic-gate smr_free_buflist(smr_slab_t *sp)
17827c478bd9Sstevel@tonic-gate {
17837c478bd9Sstevel@tonic-gate int nbufs;
17847c478bd9Sstevel@tonic-gate
17857c478bd9Sstevel@tonic-gate if (sp->sl_head == NULL)
17867c478bd9Sstevel@tonic-gate return;
17877c478bd9Sstevel@tonic-gate
17887c478bd9Sstevel@tonic-gate nbufs = (sp->sl_end - sp->sl_start) / IDN_SMR_BUFSIZE;
17897c478bd9Sstevel@tonic-gate
17907c478bd9Sstevel@tonic-gate FREESTRUCT(sp->sl_head, smr_slabbuf_t, nbufs);
17917c478bd9Sstevel@tonic-gate
17927c478bd9Sstevel@tonic-gate sp->sl_head = sp->sl_free = sp->sl_inuse = NULL;
17937c478bd9Sstevel@tonic-gate }
17947c478bd9Sstevel@tonic-gate
17957c478bd9Sstevel@tonic-gate /*
17967c478bd9Sstevel@tonic-gate * Returns: 0 Successfully located a slab.
17977c478bd9Sstevel@tonic-gate * -1 Failure.
17987c478bd9Sstevel@tonic-gate */
17997c478bd9Sstevel@tonic-gate static smr_slab_t *
smr_slab_reserve(int domid)18007c478bd9Sstevel@tonic-gate smr_slab_reserve(int domid)
18017c478bd9Sstevel@tonic-gate {
18027c478bd9Sstevel@tonic-gate register int p, nextp, s, nexts;
18037c478bd9Sstevel@tonic-gate register smr_slab_t *spa;
18047c478bd9Sstevel@tonic-gate int startp, starts;
18057c478bd9Sstevel@tonic-gate int foundone = 0;
18067c478bd9Sstevel@tonic-gate int spl;
18077c478bd9Sstevel@tonic-gate procname_t proc = "smr_slab_reserve";
18087c478bd9Sstevel@tonic-gate
18097c478bd9Sstevel@tonic-gate p = startp = SMR_SLABPOOL_HASH(domid);
18107c478bd9Sstevel@tonic-gate nextp = -1;
18117c478bd9Sstevel@tonic-gate
18127c478bd9Sstevel@tonic-gate spl = splhi();
18137c478bd9Sstevel@tonic-gate while ((nextp != startp) && !foundone) {
18147c478bd9Sstevel@tonic-gate
18157c478bd9Sstevel@tonic-gate s = starts = SMR_SLAB_HASH(p, domid);
18167c478bd9Sstevel@tonic-gate nexts = -1;
18177c478bd9Sstevel@tonic-gate spa = &(idn.slabpool->pool[p].sarray[0]);
18187c478bd9Sstevel@tonic-gate
18197c478bd9Sstevel@tonic-gate while ((nexts != starts) && !foundone) {
18207c478bd9Sstevel@tonic-gate if (lock_try(&spa[s].sl_lock)) {
18217c478bd9Sstevel@tonic-gate foundone = 1;
18227c478bd9Sstevel@tonic-gate break;
18237c478bd9Sstevel@tonic-gate }
18247c478bd9Sstevel@tonic-gate nexts = SMR_SLAB_HASHSTEP(p, s);
18257c478bd9Sstevel@tonic-gate s = nexts;
18267c478bd9Sstevel@tonic-gate }
18277c478bd9Sstevel@tonic-gate if (foundone)
18287c478bd9Sstevel@tonic-gate break;
18297c478bd9Sstevel@tonic-gate nextp = SMR_SLABPOOL_HASHSTEP(p);
18307c478bd9Sstevel@tonic-gate p = nextp;
18317c478bd9Sstevel@tonic-gate }
18327c478bd9Sstevel@tonic-gate splx(spl);
18337c478bd9Sstevel@tonic-gate
18347c478bd9Sstevel@tonic-gate if (foundone) {
18357c478bd9Sstevel@tonic-gate ASSERT((&spa[s] >= idn.slabpool->savep) &&
18367c478bd9Sstevel@tonic-gate (&spa[s] < (idn.slabpool->savep +
18377c478bd9Sstevel@tonic-gate idn.slabpool->ntotslabs)));
18387c478bd9Sstevel@tonic-gate
18397c478bd9Sstevel@tonic-gate spa[s].sl_domid = (short)domid;
18407c478bd9Sstevel@tonic-gate
18417c478bd9Sstevel@tonic-gate ATOMIC_DEC(idn.slabpool->pool[p].nfree);
18427c478bd9Sstevel@tonic-gate
18437c478bd9Sstevel@tonic-gate if (domid == idn.localid) {
18447c478bd9Sstevel@tonic-gate smr_slab_t *nsp;
18457c478bd9Sstevel@tonic-gate /*
18467c478bd9Sstevel@tonic-gate * Caller is actually reserving a slab for
18477c478bd9Sstevel@tonic-gate * themself which means they'll need the full
18487c478bd9Sstevel@tonic-gate * slab structure to represent all of the I/O
18497c478bd9Sstevel@tonic-gate * buffers. The "spa" is just a representative
18507c478bd9Sstevel@tonic-gate * and doesn't contain the space to manage the
18517c478bd9Sstevel@tonic-gate * individual buffers. Need to alloc a full-size
18527c478bd9Sstevel@tonic-gate * struct.
18537c478bd9Sstevel@tonic-gate * Note that this results in the returning
18547c478bd9Sstevel@tonic-gate * smr_slab_t structure being unlocked.
18557c478bd9Sstevel@tonic-gate */
18567c478bd9Sstevel@tonic-gate ASSERT(idn.localid == IDN_GET_MASTERID());
18577c478bd9Sstevel@tonic-gate nsp = GETSTRUCT(smr_slab_t, 1);
18587c478bd9Sstevel@tonic-gate nsp->sl_start = spa[s].sl_start;
18597c478bd9Sstevel@tonic-gate nsp->sl_end = spa[s].sl_end;
18607c478bd9Sstevel@tonic-gate smr_alloc_buflist(nsp);
18617c478bd9Sstevel@tonic-gate spa = nsp;
18627c478bd9Sstevel@tonic-gate PR_SMR("%s: allocated full slab struct for domain %d\n",
18637c478bd9Sstevel@tonic-gate proc, domid);
18647c478bd9Sstevel@tonic-gate } else {
18657c478bd9Sstevel@tonic-gate /*
18667c478bd9Sstevel@tonic-gate * Slab structure gets returned locked.
18677c478bd9Sstevel@tonic-gate */
18687c478bd9Sstevel@tonic-gate spa += s;
18697c478bd9Sstevel@tonic-gate }
18707c478bd9Sstevel@tonic-gate
1871bf30efa4Smathue PR_SMR("%s: allocated slab 0x%p (start=0x%p, size=%lu) for "
1872*07d06da5SSurya Prakki "domain %d\n", proc, (void *)spa, (void *)spa->sl_start,
18737c478bd9Sstevel@tonic-gate spa->sl_end - spa->sl_start, domid);
18747c478bd9Sstevel@tonic-gate } else {
18757c478bd9Sstevel@tonic-gate PR_SMR("%s: FAILED to allocate for domain %d\n",
18767c478bd9Sstevel@tonic-gate proc, domid);
18777c478bd9Sstevel@tonic-gate spa = NULL;
18787c478bd9Sstevel@tonic-gate }
18797c478bd9Sstevel@tonic-gate
18807c478bd9Sstevel@tonic-gate return (spa);
18817c478bd9Sstevel@tonic-gate }
18827c478bd9Sstevel@tonic-gate
18837c478bd9Sstevel@tonic-gate static void
smr_slab_unreserve(int domid,smr_slab_t * sp)18847c478bd9Sstevel@tonic-gate smr_slab_unreserve(int domid, smr_slab_t *sp)
18857c478bd9Sstevel@tonic-gate {
18867c478bd9Sstevel@tonic-gate register int p, nextp, s, nexts;
18877c478bd9Sstevel@tonic-gate register smr_slab_t *spa;
18887c478bd9Sstevel@tonic-gate int foundit = 0;
18897c478bd9Sstevel@tonic-gate int startp, starts;
18907c478bd9Sstevel@tonic-gate caddr_t bufp;
18917c478bd9Sstevel@tonic-gate procname_t proc = "smr_slab_unreserve";
18927c478bd9Sstevel@tonic-gate
18937c478bd9Sstevel@tonic-gate bufp = sp->sl_start;
18947c478bd9Sstevel@tonic-gate p = startp = SMR_SLABPOOL_HASH(domid);
18957c478bd9Sstevel@tonic-gate nextp = -1;
18967c478bd9Sstevel@tonic-gate
18977c478bd9Sstevel@tonic-gate while ((nextp != startp) && !foundit) {
18987c478bd9Sstevel@tonic-gate
18997c478bd9Sstevel@tonic-gate s = starts = SMR_SLAB_HASH(p, domid);
19007c478bd9Sstevel@tonic-gate nexts = -1;
19017c478bd9Sstevel@tonic-gate spa = &(idn.slabpool->pool[p].sarray[0]);
19027c478bd9Sstevel@tonic-gate
19037c478bd9Sstevel@tonic-gate while ((nexts != starts) && !foundit) {
19047c478bd9Sstevel@tonic-gate if (spa[s].sl_start == bufp) {
19057c478bd9Sstevel@tonic-gate foundit = 1;
19067c478bd9Sstevel@tonic-gate break;
19077c478bd9Sstevel@tonic-gate }
19087c478bd9Sstevel@tonic-gate nexts = SMR_SLAB_HASHSTEP(p, s);
19097c478bd9Sstevel@tonic-gate s = nexts;
19107c478bd9Sstevel@tonic-gate }
19117c478bd9Sstevel@tonic-gate if (foundit)
19127c478bd9Sstevel@tonic-gate break;
19137c478bd9Sstevel@tonic-gate nextp = SMR_SLABPOOL_HASHSTEP(p);
19147c478bd9Sstevel@tonic-gate p = nextp;
19157c478bd9Sstevel@tonic-gate }
19167c478bd9Sstevel@tonic-gate if (foundit) {
19177c478bd9Sstevel@tonic-gate ASSERT((&spa[s] >= idn.slabpool->savep) &&
19187c478bd9Sstevel@tonic-gate (&spa[s] < (idn.slabpool->savep +
19197c478bd9Sstevel@tonic-gate idn.slabpool->ntotslabs)));
19207c478bd9Sstevel@tonic-gate ASSERT(!lock_try(&spa[s].sl_lock));
19217c478bd9Sstevel@tonic-gate ASSERT(spa[s].sl_domid == (short)domid);
19227c478bd9Sstevel@tonic-gate
19237c478bd9Sstevel@tonic-gate spa[s].sl_next = NULL;
19247c478bd9Sstevel@tonic-gate spa[s].sl_domid = (short)IDN_NIL_DOMID;
19257c478bd9Sstevel@tonic-gate lock_clear(&spa[s].sl_lock);
19267c478bd9Sstevel@tonic-gate
19277c478bd9Sstevel@tonic-gate ATOMIC_INC(idn.slabpool->pool[p].nfree);
19287c478bd9Sstevel@tonic-gate
1929bf30efa4Smathue PR_SMR("%s: freed (bufp=0x%p) for domain %d\n",
1930*07d06da5SSurya Prakki proc, (void *)bufp, domid);
19317c478bd9Sstevel@tonic-gate
19327c478bd9Sstevel@tonic-gate if (domid == idn.localid) {
19337c478bd9Sstevel@tonic-gate /*
19347c478bd9Sstevel@tonic-gate * Caller is actually unreserving a slab of their
19357c478bd9Sstevel@tonic-gate * own. Note that only the master calls this
19367c478bd9Sstevel@tonic-gate * routine. Since the master's local slab
19377c478bd9Sstevel@tonic-gate * structures do not get entered into the global
19387c478bd9Sstevel@tonic-gate * "representative" pool, we need to free up the
19397c478bd9Sstevel@tonic-gate * data structure that was passed in.
19407c478bd9Sstevel@tonic-gate */
19417c478bd9Sstevel@tonic-gate ASSERT(idn.localid == IDN_GET_MASTERID());
19427c478bd9Sstevel@tonic-gate ASSERT(sp != &spa[s]);
19437c478bd9Sstevel@tonic-gate
19447c478bd9Sstevel@tonic-gate smr_free_buflist(sp);
19457c478bd9Sstevel@tonic-gate FREESTRUCT(sp, smr_slab_t, 1);
19467c478bd9Sstevel@tonic-gate } else {
19477c478bd9Sstevel@tonic-gate ASSERT(sp == &spa[s]);
19487c478bd9Sstevel@tonic-gate }
19497c478bd9Sstevel@tonic-gate } else {
19507c478bd9Sstevel@tonic-gate /*
19517c478bd9Sstevel@tonic-gate * Couldn't find slab entry for given buf!
19527c478bd9Sstevel@tonic-gate */
1953bf30efa4Smathue PR_SMR("%s: FAILED to free (bufp=0x%p) for domain %d\n",
1954*07d06da5SSurya Prakki proc, (void *)bufp, domid);
19557c478bd9Sstevel@tonic-gate }
19567c478bd9Sstevel@tonic-gate }
19577c478bd9Sstevel@tonic-gate
19587c478bd9Sstevel@tonic-gate /*
19597c478bd9Sstevel@tonic-gate * The Reap Protocol:
19607c478bd9Sstevel@tonic-gate * master slave
19617c478bd9Sstevel@tonic-gate * ------ -----
19627c478bd9Sstevel@tonic-gate * smr_slab_reap_global
19637c478bd9Sstevel@tonic-gate * - idn_broadcast_cmd(SLABREAP) -> idn_recv_cmd(SLABREAP)
19647c478bd9Sstevel@tonic-gate * . idn_local_cmd(SLABREAP) - idn_recv_slabreap_req
19657c478bd9Sstevel@tonic-gate * - smr_slab_reap . smr_slab_reap
19667c478bd9Sstevel@tonic-gate * . smr_slaballoc_get_n - smr_slaballoc_get_n
19677c478bd9Sstevel@tonic-gate * . smr_slab_free - smr_slab_free
19687c478bd9Sstevel@tonic-gate * - smr_slab_free_local . smr_slab_free_remote
19697c478bd9Sstevel@tonic-gate * . smr_slab_unreserve
19707c478bd9Sstevel@tonic-gate * <- - idn_send_cmd(SLABFREE)
19717c478bd9Sstevel@tonic-gate * idn_recv_cmd(SLABFREE)
19727c478bd9Sstevel@tonic-gate * - idn_recv_slabfree_req
19737c478bd9Sstevel@tonic-gate * . smr_slaballoc_get
19747c478bd9Sstevel@tonic-gate * . smr_slab_free
19757c478bd9Sstevel@tonic-gate * - smr_slab_free_local
19767c478bd9Sstevel@tonic-gate * . smr_slab_unreserve
19777c478bd9Sstevel@tonic-gate * . idn_send_slabfree_resp -> idn_recv_cmd(SLABFREE | ack)
19787c478bd9Sstevel@tonic-gate * - idn_recv_slabfree_resp
19797c478bd9Sstevel@tonic-gate *
19807c478bd9Sstevel@tonic-gate * idn_recv_cmd(SLABREAP | ack) <- . idn_send_slabreap_resp
19817c478bd9Sstevel@tonic-gate * - idn_recv_slabreap_resp DONE
19827c478bd9Sstevel@tonic-gate * DONE
19837c478bd9Sstevel@tonic-gate *
19847c478bd9Sstevel@tonic-gate * Check available slabs and if we're below the threshold, kick
19857c478bd9Sstevel@tonic-gate * off reaping to all remote domains. There is no guarantee remote
19867c478bd9Sstevel@tonic-gate * domains will be able to free up any.
19877c478bd9Sstevel@tonic-gate */
19887c478bd9Sstevel@tonic-gate static void
smr_slab_reap_global()19897c478bd9Sstevel@tonic-gate smr_slab_reap_global()
19907c478bd9Sstevel@tonic-gate {
19917c478bd9Sstevel@tonic-gate register int p, npools;
19927c478bd9Sstevel@tonic-gate register int total_free = 0;
19937c478bd9Sstevel@tonic-gate register struct smr_slabtbl *tblp;
19947c478bd9Sstevel@tonic-gate static clock_t reap_last = 0;
19957c478bd9Sstevel@tonic-gate procname_t proc = "smr_slab_reap_global";
1996d3d50737SRafael Vanoni clock_t now;
19977c478bd9Sstevel@tonic-gate
19987c478bd9Sstevel@tonic-gate ASSERT(IDN_GET_MASTERID() != IDN_NIL_DOMID);
19997c478bd9Sstevel@tonic-gate
20007c478bd9Sstevel@tonic-gate DSLAB_LOCK_SHARED(idn.localid);
20017c478bd9Sstevel@tonic-gate if (idn_domain[idn.localid].dslab_state != DSLAB_STATE_LOCAL) {
20027c478bd9Sstevel@tonic-gate PR_SMR("%s: only allowed by master (%d)\n",
20037c478bd9Sstevel@tonic-gate proc, IDN_GET_MASTERID());
20047c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid);
20057c478bd9Sstevel@tonic-gate return;
20067c478bd9Sstevel@tonic-gate }
20077c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid);
20087c478bd9Sstevel@tonic-gate
2009d3d50737SRafael Vanoni now = ddi_get_lbolt();
2010d3d50737SRafael Vanoni if ((now > 0) && (now > reap_last) &&
2011d3d50737SRafael Vanoni ((now - reap_last) < IDN_REAP_INTERVAL))
20127c478bd9Sstevel@tonic-gate return;
20137c478bd9Sstevel@tonic-gate
2014d3d50737SRafael Vanoni reap_last = now;
20157c478bd9Sstevel@tonic-gate
20167c478bd9Sstevel@tonic-gate ASSERT(idn.slabpool);
20177c478bd9Sstevel@tonic-gate
20187c478bd9Sstevel@tonic-gate npools = idn.slabpool->npools;
20197c478bd9Sstevel@tonic-gate tblp = idn.slabpool->pool;
20207c478bd9Sstevel@tonic-gate
20217c478bd9Sstevel@tonic-gate for (p = 0; p < npools; tblp++, p++)
20227c478bd9Sstevel@tonic-gate total_free += tblp->nfree;
20237c478bd9Sstevel@tonic-gate
20247c478bd9Sstevel@tonic-gate if (total_free <= IDN_SLAB_THRESHOLD) {
20257c478bd9Sstevel@tonic-gate int diff, reap_per_domain;
20267c478bd9Sstevel@tonic-gate
20277c478bd9Sstevel@tonic-gate PR_SMR("%s: kicking off reaping "
2028bf30efa4Smathue "(total_free = %d, min = %d)\n",
20297c478bd9Sstevel@tonic-gate proc, total_free, IDN_SLAB_THRESHOLD);
20307c478bd9Sstevel@tonic-gate
20317c478bd9Sstevel@tonic-gate diff = IDN_SLAB_THRESHOLD - total_free;
2032d3d50737SRafael Vanoni reap_per_domain = (diff < idn.ndomains) ?
2033d3d50737SRafael Vanoni 1 : (diff / idn.ndomains);
20347c478bd9Sstevel@tonic-gate
20357c478bd9Sstevel@tonic-gate idn_broadcast_cmd(IDNCMD_SLABREAP, reap_per_domain, 0, 0);
20367c478bd9Sstevel@tonic-gate }
20377c478bd9Sstevel@tonic-gate }
20387c478bd9Sstevel@tonic-gate
20397c478bd9Sstevel@tonic-gate void
smr_slab_reap(int domid,int * nslabs)20407c478bd9Sstevel@tonic-gate smr_slab_reap(int domid, int *nslabs)
20417c478bd9Sstevel@tonic-gate {
20427c478bd9Sstevel@tonic-gate register int d;
20437c478bd9Sstevel@tonic-gate int nreclaimed;
20447c478bd9Sstevel@tonic-gate smr_slab_t *sp;
20457c478bd9Sstevel@tonic-gate domainset_t reapset;
20467c478bd9Sstevel@tonic-gate procname_t proc = "smr_slab_reap";
20477c478bd9Sstevel@tonic-gate
20487c478bd9Sstevel@tonic-gate /*
20497c478bd9Sstevel@tonic-gate * Should only be called on behalf of local
20507c478bd9Sstevel@tonic-gate * domain.
20517c478bd9Sstevel@tonic-gate */
20527c478bd9Sstevel@tonic-gate if (domid != idn.localid) {
20537c478bd9Sstevel@tonic-gate PR_SMR("%s: called by domain %d, should only be local (%d)\n",
20547c478bd9Sstevel@tonic-gate proc, domid, idn.localid);
20557c478bd9Sstevel@tonic-gate ASSERT(0);
20567c478bd9Sstevel@tonic-gate return;
20577c478bd9Sstevel@tonic-gate }
20587c478bd9Sstevel@tonic-gate /*
20597c478bd9Sstevel@tonic-gate * Try and reclaim some buffers so we can possibly
20607c478bd9Sstevel@tonic-gate * free up some slabs.
20617c478bd9Sstevel@tonic-gate */
20627c478bd9Sstevel@tonic-gate reapset = idn.domset.ds_connected;
20637c478bd9Sstevel@tonic-gate
20647c478bd9Sstevel@tonic-gate IDN_GKSTAT_GLOBAL_EVENT(gk_reaps, gk_reap_last);
20657c478bd9Sstevel@tonic-gate
20667c478bd9Sstevel@tonic-gate nreclaimed = 0;
20677c478bd9Sstevel@tonic-gate for (d = 0; d < MAX_DOMAINS; d++) {
20687c478bd9Sstevel@tonic-gate int nr;
20697c478bd9Sstevel@tonic-gate idn_domain_t *dp;
20707c478bd9Sstevel@tonic-gate
20717c478bd9Sstevel@tonic-gate if (!DOMAIN_IN_SET(reapset, d))
20727c478bd9Sstevel@tonic-gate continue;
20737c478bd9Sstevel@tonic-gate
20747c478bd9Sstevel@tonic-gate IDN_DLOCK_SHARED(d);
20757c478bd9Sstevel@tonic-gate
20767c478bd9Sstevel@tonic-gate dp = &idn_domain[d];
20777c478bd9Sstevel@tonic-gate if ((d == idn.localid) || (dp->dcpu < 0)) {
20787c478bd9Sstevel@tonic-gate IDN_DUNLOCK(d);
20797c478bd9Sstevel@tonic-gate continue;
20807c478bd9Sstevel@tonic-gate }
20817c478bd9Sstevel@tonic-gate /*
20827c478bd9Sstevel@tonic-gate * Clean up any dead I/O errors if possible.
20837c478bd9Sstevel@tonic-gate */
20847c478bd9Sstevel@tonic-gate if (dp->dioerr > 0) {
20857c478bd9Sstevel@tonic-gate idn_domain_t *ldp;
20867c478bd9Sstevel@tonic-gate register int cnt;
20877c478bd9Sstevel@tonic-gate register smr_slabbuf_t *bp;
20887c478bd9Sstevel@tonic-gate /*
20897c478bd9Sstevel@tonic-gate * We need to grab the writer lock to prevent
20907c478bd9Sstevel@tonic-gate * anybody from allocating buffers while we
20917c478bd9Sstevel@tonic-gate * traverse the slabs outstanding.
20927c478bd9Sstevel@tonic-gate */
20937c478bd9Sstevel@tonic-gate cnt = 0;
20947c478bd9Sstevel@tonic-gate ldp = &idn_domain[idn.localid];
20957c478bd9Sstevel@tonic-gate IDN_DLOCK_EXCL(idn.localid);
20967c478bd9Sstevel@tonic-gate DSLAB_LOCK_EXCL(idn.localid);
20977c478bd9Sstevel@tonic-gate for (sp = ldp->dslab; sp; sp = sp->sl_next)
20987c478bd9Sstevel@tonic-gate for (bp = sp->sl_inuse; bp; bp = bp->sb_next)
20997c478bd9Sstevel@tonic-gate if (bp->sb_domid == d)
21007c478bd9Sstevel@tonic-gate cnt++;
21017c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(idn.localid);
21027c478bd9Sstevel@tonic-gate ASSERT((dp->dio + dp->dioerr) >= cnt);
21037c478bd9Sstevel@tonic-gate dp->dio = cnt;
21047c478bd9Sstevel@tonic-gate dp->dioerr = 0;
21057c478bd9Sstevel@tonic-gate IDN_DUNLOCK(idn.localid);
21067c478bd9Sstevel@tonic-gate }
21077c478bd9Sstevel@tonic-gate if ((dp->dstate == IDNDS_CONNECTED) &&
21087c478bd9Sstevel@tonic-gate ((nr = idn_reclaim_mboxdata(d, 0, -1)) > 0))
21097c478bd9Sstevel@tonic-gate nreclaimed += nr;
21107c478bd9Sstevel@tonic-gate
21117c478bd9Sstevel@tonic-gate IDN_DUNLOCK(d);
21127c478bd9Sstevel@tonic-gate }
21137c478bd9Sstevel@tonic-gate
21147c478bd9Sstevel@tonic-gate DSLAB_LOCK_EXCL(domid);
21157c478bd9Sstevel@tonic-gate sp = smr_slaballoc_get_n(domid, nslabs);
21167c478bd9Sstevel@tonic-gate if (sp) {
21177c478bd9Sstevel@tonic-gate IDN_GKSTAT_ADD(gk_reap_count, (ulong_t)(*nslabs));
21187c478bd9Sstevel@tonic-gate smr_slab_free(domid, sp);
21197c478bd9Sstevel@tonic-gate }
21207c478bd9Sstevel@tonic-gate DSLAB_UNLOCK(domid);
21217c478bd9Sstevel@tonic-gate }
21227c478bd9Sstevel@tonic-gate
21237c478bd9Sstevel@tonic-gate /*
21247c478bd9Sstevel@tonic-gate * ---------------------------------------------------------------------
21257c478bd9Sstevel@tonic-gate * Remap the (IDN) shared memory region to a new physical address.
21267c478bd9Sstevel@tonic-gate * Caller is expected to have performed a ecache flush if needed.
21277c478bd9Sstevel@tonic-gate * ---------------------------------------------------------------------
21287c478bd9Sstevel@tonic-gate */
21297c478bd9Sstevel@tonic-gate void
smr_remap(struct as * as,register caddr_t vaddr,register pfn_t new_pfn,uint_t mblen)21307c478bd9Sstevel@tonic-gate smr_remap(struct as *as, register caddr_t vaddr,
21317c478bd9Sstevel@tonic-gate register pfn_t new_pfn, uint_t mblen)
21327c478bd9Sstevel@tonic-gate {
21337c478bd9Sstevel@tonic-gate tte_t tte;
21347c478bd9Sstevel@tonic-gate size_t blen;
21357c478bd9Sstevel@tonic-gate pgcnt_t p, npgs;
21367c478bd9Sstevel@tonic-gate procname_t proc = "smr_remap";
21377c478bd9Sstevel@tonic-gate
21387c478bd9Sstevel@tonic-gate if (va_to_pfn(vaddr) == new_pfn) {
2139bf30efa4Smathue PR_REMAP("%s: vaddr (0x%p) already mapped to pfn (0x%lx)\n",
2140*07d06da5SSurya Prakki proc, (void *)vaddr, new_pfn);
21417c478bd9Sstevel@tonic-gate return;
21427c478bd9Sstevel@tonic-gate }
21437c478bd9Sstevel@tonic-gate
21447c478bd9Sstevel@tonic-gate blen = MB2B(mblen);
21457c478bd9Sstevel@tonic-gate npgs = btopr(blen);
21467c478bd9Sstevel@tonic-gate ASSERT(npgs != 0);
21477c478bd9Sstevel@tonic-gate
2148bf30efa4Smathue PR_REMAP("%s: va = 0x%p, pfn = 0x%lx, npgs = %ld, mb = %d MB (%ld)\n",
2149*07d06da5SSurya Prakki proc, (void *)vaddr, new_pfn, npgs, mblen, blen);
21507c478bd9Sstevel@tonic-gate
21517c478bd9Sstevel@tonic-gate /*
21527c478bd9Sstevel@tonic-gate * Unmap the SMR virtual address from it's current
21537c478bd9Sstevel@tonic-gate * mapping.
21547c478bd9Sstevel@tonic-gate */
21557c478bd9Sstevel@tonic-gate hat_unload(as->a_hat, vaddr, blen, HAT_UNLOAD_UNLOCK);
21567c478bd9Sstevel@tonic-gate
21577c478bd9Sstevel@tonic-gate if (new_pfn == PFN_INVALID)
21587c478bd9Sstevel@tonic-gate return;
21597c478bd9Sstevel@tonic-gate
21607c478bd9Sstevel@tonic-gate /*
21617c478bd9Sstevel@tonic-gate * Map the SMR to the new physical address space,
21627c478bd9Sstevel@tonic-gate * presumably a remote pfn. Cannot use hat_devload
21637c478bd9Sstevel@tonic-gate * because it will think pfn represents non-memory,
21647c478bd9Sstevel@tonic-gate * i.e. space since it may beyond his physmax.
21657c478bd9Sstevel@tonic-gate */
21667c478bd9Sstevel@tonic-gate for (p = 0; p < npgs; p++) {
2167d3d50737SRafael Vanoni sfmmu_memtte(&tte, new_pfn, PROT_READ | PROT_WRITE | HAT_NOSYNC,
21687c478bd9Sstevel@tonic-gate TTE8K);
21697c478bd9Sstevel@tonic-gate sfmmu_tteload(as->a_hat, &tte, vaddr, NULL, HAT_LOAD_LOCK);
21707c478bd9Sstevel@tonic-gate
21717c478bd9Sstevel@tonic-gate vaddr += MMU_PAGESIZE;
21727c478bd9Sstevel@tonic-gate new_pfn++;
21737c478bd9Sstevel@tonic-gate }
21747c478bd9Sstevel@tonic-gate
21757c478bd9Sstevel@tonic-gate PR_REMAP("%s: remapped %ld pages (expected %ld)\n",
21767c478bd9Sstevel@tonic-gate proc, npgs, btopr(MB2B(mblen)));
21777c478bd9Sstevel@tonic-gate }
2178