xref: /dragonfly/sys/kern/kern_sysref.c (revision dd0e3cd7)
110aa77c0SMatthew Dillon /*
210aa77c0SMatthew Dillon  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
310aa77c0SMatthew Dillon  *
410aa77c0SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
510aa77c0SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
610aa77c0SMatthew Dillon  *
710aa77c0SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
810aa77c0SMatthew Dillon  * modification, are permitted provided that the following conditions
910aa77c0SMatthew Dillon  * are met:
1010aa77c0SMatthew Dillon  *
1110aa77c0SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
1210aa77c0SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
1310aa77c0SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
1410aa77c0SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
1510aa77c0SMatthew Dillon  *    the documentation and/or other materials provided with the
1610aa77c0SMatthew Dillon  *    distribution.
1710aa77c0SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
1810aa77c0SMatthew Dillon  *    contributors may be used to endorse or promote products derived
1910aa77c0SMatthew Dillon  *    from this software without specific, prior written permission.
2010aa77c0SMatthew Dillon  *
2110aa77c0SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2210aa77c0SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2310aa77c0SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2410aa77c0SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
2510aa77c0SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2610aa77c0SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2710aa77c0SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2810aa77c0SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2910aa77c0SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3010aa77c0SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3110aa77c0SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3210aa77c0SMatthew Dillon  * SUCH DAMAGE.
3310aa77c0SMatthew Dillon  */
3410aa77c0SMatthew Dillon /*
3510aa77c0SMatthew Dillon  * System resource control module for all cluster-addressable system resource
3610aa77c0SMatthew Dillon  * structures.
3710aa77c0SMatthew Dillon  *
3810aa77c0SMatthew Dillon  * This module implements the core ref counting, sysid registration, and
3910aa77c0SMatthew Dillon  * objcache-backed allocation mechanism for all major system resource
4010aa77c0SMatthew Dillon  * structures.
4110aa77c0SMatthew Dillon  *
4210aa77c0SMatthew Dillon  * sysid registrations operate via the objcache ctor/dtor mechanism and
4310aa77c0SMatthew Dillon  * sysids will be reused if the resource is not explicitly accessed via
4410aa77c0SMatthew Dillon  * its sysid.  This removes all RB tree handling overhead from the critical
4510aa77c0SMatthew Dillon  * path for locally used resources.
4610aa77c0SMatthew Dillon  */
4710aa77c0SMatthew Dillon 
4810aa77c0SMatthew Dillon #include <sys/param.h>
4910aa77c0SMatthew Dillon #include <sys/systm.h>
5010aa77c0SMatthew Dillon #include <sys/kernel.h>
51dae65060Szrj #include <sys/malloc.h>
5210aa77c0SMatthew Dillon #include <sys/tree.h>
5310aa77c0SMatthew Dillon #include <sys/spinlock.h>
5410aa77c0SMatthew Dillon #include <machine/atomic.h>
5510aa77c0SMatthew Dillon #include <machine/cpufunc.h>
5610aa77c0SMatthew Dillon 
5710aa77c0SMatthew Dillon #include <sys/spinlock2.h>
5810aa77c0SMatthew Dillon #include <sys/sysref2.h>
5910aa77c0SMatthew Dillon 
60698331b0SMatthew Dillon static boolean_t sysref_ctor(void *data, void *privdata, int ocflags);
61698331b0SMatthew Dillon static void sysref_dtor(void *data, void *privdata);
6210aa77c0SMatthew Dillon 
6310aa77c0SMatthew Dillon /*
6410aa77c0SMatthew Dillon  * Red-Black tree support
6510aa77c0SMatthew Dillon  */
6610aa77c0SMatthew Dillon static int rb_sysref_compare(struct sysref *sr1, struct sysref *sr2);
6710aa77c0SMatthew Dillon RB_GENERATE2(sysref_rb_tree, sysref, rbnode, rb_sysref_compare, sysid_t, sysid);
6810aa77c0SMatthew Dillon 
6910aa77c0SMatthew Dillon static struct srpercpu {
7010aa77c0SMatthew Dillon 	struct sysref_rb_tree rbtree;
7110aa77c0SMatthew Dillon 	struct spinlock spin;
7210aa77c0SMatthew Dillon } sysref_array[MAXCPU];
7310aa77c0SMatthew Dillon 
7410aa77c0SMatthew Dillon static void
sysrefbootinit(void * dummy __unused)7510aa77c0SMatthew Dillon sysrefbootinit(void *dummy __unused)
7610aa77c0SMatthew Dillon {
7710aa77c0SMatthew Dillon 	struct srpercpu *sa;
7810aa77c0SMatthew Dillon 	int i;
7910aa77c0SMatthew Dillon 
8010aa77c0SMatthew Dillon 	for (i = 0; i < ncpus; ++i) {
8110aa77c0SMatthew Dillon 		sa = &sysref_array[i];
82ba87a4abSSascha Wildner 		spin_init(&sa->spin, "sysrefbootinit");
8310aa77c0SMatthew Dillon 		RB_INIT(&sa->rbtree);
8410aa77c0SMatthew Dillon 	}
8510aa77c0SMatthew Dillon }
8610aa77c0SMatthew Dillon 
87ba39e2e0SMatthew Dillon SYSINIT(sysref, SI_BOOT2_MACHDEP, SI_ORDER_ANY, sysrefbootinit, NULL);
8810aa77c0SMatthew Dillon 
8910aa77c0SMatthew Dillon static
9010aa77c0SMatthew Dillon int
rb_sysref_compare(struct sysref * sr1,struct sysref * sr2)9110aa77c0SMatthew Dillon rb_sysref_compare(struct sysref *sr1, struct sysref *sr2)
9210aa77c0SMatthew Dillon {
9310aa77c0SMatthew Dillon 	if (sr1->sysid < sr2->sysid)
9410aa77c0SMatthew Dillon 		return(-1);
9510aa77c0SMatthew Dillon 	if (sr1->sysid > sr2->sysid)
9610aa77c0SMatthew Dillon 		return(1);
9710aa77c0SMatthew Dillon 	return(0);
9810aa77c0SMatthew Dillon }
9910aa77c0SMatthew Dillon 
10010aa77c0SMatthew Dillon /*
10110aa77c0SMatthew Dillon  * Manual initialization of a resource structure's sysref, only used during
10210aa77c0SMatthew Dillon  * booting to set up certain statically declared resources which cannot
10310aa77c0SMatthew Dillon  * be deallocated.
10410aa77c0SMatthew Dillon  */
10510aa77c0SMatthew Dillon void
sysref_init(struct sysref * sr,struct sysref_class * srclass)106698331b0SMatthew Dillon sysref_init(struct sysref *sr, struct sysref_class *srclass)
10710aa77c0SMatthew Dillon {
10810aa77c0SMatthew Dillon 	struct srpercpu *sa;
10910aa77c0SMatthew Dillon 	globaldata_t gd;
11010aa77c0SMatthew Dillon 
11110aa77c0SMatthew Dillon 	gd = mycpu;
11210aa77c0SMatthew Dillon 	crit_enter_gd(gd);
11310aa77c0SMatthew Dillon 	gd->gd_sysid_alloc += ncpus_fit; /* next unique sysid */
11410aa77c0SMatthew Dillon 	sr->sysid = gd->gd_sysid_alloc;
11510aa77c0SMatthew Dillon 	KKASSERT(((int)sr->sysid & ncpus_fit_mask) == gd->gd_cpuid);
11610aa77c0SMatthew Dillon 	sr->refcnt = -0x40000000;
11710aa77c0SMatthew Dillon 	sr->flags = 0;
118698331b0SMatthew Dillon 	sr->srclass = srclass;
11910aa77c0SMatthew Dillon 
12010aa77c0SMatthew Dillon 	sa = &sysref_array[gd->gd_cpuid];
121287a8577SAlex Hornung 	spin_lock(&sa->spin);
12210aa77c0SMatthew Dillon 	sysref_rb_tree_RB_INSERT(&sa->rbtree, sr);
123287a8577SAlex Hornung 	spin_unlock(&sa->spin);
12410aa77c0SMatthew Dillon 	crit_exit_gd(gd);
12510aa77c0SMatthew Dillon }
12610aa77c0SMatthew Dillon 
12710aa77c0SMatthew Dillon /*
12810aa77c0SMatthew Dillon  * Allocate a resource structure of the specified class, initialize a
12910aa77c0SMatthew Dillon  * sysid and add the resource to the RB tree.  The caller must complete
13010aa77c0SMatthew Dillon  * initialization of the resource and call sysref_activate() to activate it.
13110aa77c0SMatthew Dillon  */
13210aa77c0SMatthew Dillon void *
sysref_alloc(struct sysref_class * srclass)133698331b0SMatthew Dillon sysref_alloc(struct sysref_class *srclass)
13410aa77c0SMatthew Dillon {
13510aa77c0SMatthew Dillon 	struct sysref *sr;
13610aa77c0SMatthew Dillon 	char *data;
13710aa77c0SMatthew Dillon 	int n;
13810aa77c0SMatthew Dillon 
13910aa77c0SMatthew Dillon 	/*
14010aa77c0SMatthew Dillon 	 * Create the object cache backing store.
14110aa77c0SMatthew Dillon 	 */
142698331b0SMatthew Dillon 	if (srclass->oc == NULL) {
143698331b0SMatthew Dillon 		KKASSERT(srclass->mtype != NULL);
144698331b0SMatthew Dillon 		srclass->oc = objcache_create_mbacked(
145698331b0SMatthew Dillon 				srclass->mtype, srclass->objsize,
1462fce2579SSepherosa Ziehau 				0, srclass->nom_cache,
147698331b0SMatthew Dillon 				sysref_ctor, sysref_dtor, srclass);
14810aa77c0SMatthew Dillon 	}
14910aa77c0SMatthew Dillon 
15010aa77c0SMatthew Dillon 	/*
15110aa77c0SMatthew Dillon 	 * Allocate the resource.
15210aa77c0SMatthew Dillon 	 */
153698331b0SMatthew Dillon 	data = objcache_get(srclass->oc, M_WAITOK);
154698331b0SMatthew Dillon 	sr = (struct sysref *)(data + srclass->offset);
15518b4c2bbSMatthew Dillon 	KKASSERT(sr->flags & SRF_PUTAWAY);
15618b4c2bbSMatthew Dillon 	sr->flags &= ~SRF_PUTAWAY;
15710aa77c0SMatthew Dillon 
15810aa77c0SMatthew Dillon 	/*
15910aa77c0SMatthew Dillon 	 * Refcnt isn't touched while it is zero.  The objcache ctor
16010aa77c0SMatthew Dillon 	 * function has already allocated a sysid and emplaced the
16110aa77c0SMatthew Dillon 	 * structure in the RB tree.
16210aa77c0SMatthew Dillon 	 */
16310aa77c0SMatthew Dillon 	KKASSERT(sr->refcnt == 0);
16410aa77c0SMatthew Dillon 	sr->refcnt = -0x40000000;
16510aa77c0SMatthew Dillon 
16610aa77c0SMatthew Dillon 	/*
16710aa77c0SMatthew Dillon 	 * Clean out the structure unless the caller wants to deal with
16810aa77c0SMatthew Dillon 	 * it (e.g. like the vmspace code).
16910aa77c0SMatthew Dillon 	 */
170698331b0SMatthew Dillon 	if ((srclass->flags & SRC_MANAGEDINIT) == 0) {
171698331b0SMatthew Dillon 		if (srclass->offset != 0)
172698331b0SMatthew Dillon 			bzero(data, srclass->offset);
173698331b0SMatthew Dillon 		n = srclass->offset + sizeof(struct sysref);
174698331b0SMatthew Dillon 		KKASSERT(n <= srclass->objsize);
175698331b0SMatthew Dillon 		if (n != srclass->objsize)
176698331b0SMatthew Dillon 			bzero(data + n, srclass->objsize - n);
17710aa77c0SMatthew Dillon 	}
17810aa77c0SMatthew Dillon 	return(data);
17910aa77c0SMatthew Dillon }
18010aa77c0SMatthew Dillon 
18110aa77c0SMatthew Dillon /*
18210aa77c0SMatthew Dillon  * Object cache backing store ctor function.
18310aa77c0SMatthew Dillon  *
18410aa77c0SMatthew Dillon  * This allocates the sysid and associates the structure with the
18510aa77c0SMatthew Dillon  * red-black tree, allowing it to be looked up.  The actual resource
18610aa77c0SMatthew Dillon  * structure has NOT yet been allocated so it is marked free.
18710aa77c0SMatthew Dillon  *
18810aa77c0SMatthew Dillon  * If the sysid is not used to access the resource, we will just
18910aa77c0SMatthew Dillon  * allow the sysid to be reused when the resource structure is reused,
19010aa77c0SMatthew Dillon  * allowing the RB tree operation to be 'cached'.  This results in
19110aa77c0SMatthew Dillon  * virtually no performance penalty for using the sysref facility.
19210aa77c0SMatthew Dillon  */
19310aa77c0SMatthew Dillon static
19410aa77c0SMatthew Dillon boolean_t
sysref_ctor(void * data,void * privdata,int ocflags)195698331b0SMatthew Dillon sysref_ctor(void *data, void *privdata, int ocflags)
19610aa77c0SMatthew Dillon {
19710aa77c0SMatthew Dillon 	globaldata_t gd;
19810aa77c0SMatthew Dillon 	struct srpercpu *sa;
199698331b0SMatthew Dillon 	struct sysref_class *srclass = privdata;
200698331b0SMatthew Dillon 	struct sysref *sr = (void *)((char *)data + srclass->offset);
20110aa77c0SMatthew Dillon 
20210aa77c0SMatthew Dillon 	/*
20310aa77c0SMatthew Dillon 	 * Resource structures need to be cleared when allocating from
20410aa77c0SMatthew Dillon 	 * malloc backing store.  This is different from the zeroing
20510aa77c0SMatthew Dillon 	 * that we do in sysref_alloc().
20610aa77c0SMatthew Dillon 	 */
207698331b0SMatthew Dillon 	bzero(data, srclass->objsize);
20810aa77c0SMatthew Dillon 
20910aa77c0SMatthew Dillon 	/*
21010aa77c0SMatthew Dillon 	 * Resources managed by our objcache do the sysid and RB tree
21110aa77c0SMatthew Dillon 	 * handling in the objcache ctor/dtor, so we can reuse the
21210aa77c0SMatthew Dillon 	 * structure without re-treeing it over and over again.
21310aa77c0SMatthew Dillon 	 */
21410aa77c0SMatthew Dillon 	gd = mycpu;
21510aa77c0SMatthew Dillon 	crit_enter_gd(gd);
21610aa77c0SMatthew Dillon 	gd->gd_sysid_alloc += ncpus_fit; /* next unique sysid */
21710aa77c0SMatthew Dillon 	sr->sysid = gd->gd_sysid_alloc;
21810aa77c0SMatthew Dillon 	KKASSERT(((int)sr->sysid & ncpus_fit_mask) == gd->gd_cpuid);
21910aa77c0SMatthew Dillon 	/* sr->refcnt= 0; already zero */
22018b4c2bbSMatthew Dillon 	sr->flags = SRF_ALLOCATED | SRF_PUTAWAY;
221698331b0SMatthew Dillon 	sr->srclass = srclass;
22210aa77c0SMatthew Dillon 
22310aa77c0SMatthew Dillon 	sa = &sysref_array[gd->gd_cpuid];
224287a8577SAlex Hornung 	spin_lock(&sa->spin);
22510aa77c0SMatthew Dillon 	sysref_rb_tree_RB_INSERT(&sa->rbtree, sr);
226287a8577SAlex Hornung 	spin_unlock(&sa->spin);
22710aa77c0SMatthew Dillon 	crit_exit_gd(gd);
22810aa77c0SMatthew Dillon 
22910aa77c0SMatthew Dillon 	/*
23010aa77c0SMatthew Dillon 	 * Execute the class's ctor function, if any.  NOTE: The class
23110aa77c0SMatthew Dillon 	 * should not try to zero out the structure, we've already handled
23210aa77c0SMatthew Dillon 	 * that and preinitialized the sysref.
23310aa77c0SMatthew Dillon 	 *
23410aa77c0SMatthew Dillon 	 * XXX ignores return value for now
23510aa77c0SMatthew Dillon 	 */
236698331b0SMatthew Dillon 	if (srclass->ctor)
237698331b0SMatthew Dillon 		srclass->ctor(data, privdata, ocflags);
23810aa77c0SMatthew Dillon 	return TRUE;
23910aa77c0SMatthew Dillon }
24010aa77c0SMatthew Dillon 
24110aa77c0SMatthew Dillon /*
24210aa77c0SMatthew Dillon  * Object cache destructor, allowing the structure to be returned
24310aa77c0SMatthew Dillon  * to the system memory pool.  The resource structure must be
24410aa77c0SMatthew Dillon  * removed from the RB tree.  All other references have already
24510aa77c0SMatthew Dillon  * been destroyed and the RB tree will not create any new references
24610aa77c0SMatthew Dillon  * to the structure in its current state.
24710aa77c0SMatthew Dillon  */
24810aa77c0SMatthew Dillon static
24910aa77c0SMatthew Dillon void
sysref_dtor(void * data,void * privdata)250698331b0SMatthew Dillon sysref_dtor(void *data, void *privdata)
25110aa77c0SMatthew Dillon {
25210aa77c0SMatthew Dillon 	struct srpercpu *sa;
253698331b0SMatthew Dillon 	struct sysref_class *srclass = privdata;
254698331b0SMatthew Dillon 	struct sysref *sr = (void *)((char *)data + srclass->offset);
25510aa77c0SMatthew Dillon 
25610aa77c0SMatthew Dillon 	KKASSERT(sr->refcnt == 0);
25710aa77c0SMatthew Dillon 	sa = &sysref_array[(int)sr->sysid & ncpus_fit_mask];
258287a8577SAlex Hornung 	spin_lock(&sa->spin);
25910aa77c0SMatthew Dillon 	sysref_rb_tree_RB_REMOVE(&sa->rbtree, sr);
260287a8577SAlex Hornung 	spin_unlock(&sa->spin);
261698331b0SMatthew Dillon 	if (srclass->dtor)
262698331b0SMatthew Dillon 		srclass->dtor(data, privdata);
26310aa77c0SMatthew Dillon }
26410aa77c0SMatthew Dillon 
26510aa77c0SMatthew Dillon /*
26610aa77c0SMatthew Dillon  * Activate or reactivate a resource. 0x40000001 is added to the ref count
26710aa77c0SMatthew Dillon  * so -0x40000000 (during initialization) will translate to a ref count of 1.
26810aa77c0SMatthew Dillon  * Any references made during initialization will translate to additional
26910aa77c0SMatthew Dillon  * positive ref counts.
270b0911300SMatthew Dillon  *
271b0911300SMatthew Dillon  * MPSAFE
27210aa77c0SMatthew Dillon  */
27310aa77c0SMatthew Dillon void
sysref_activate(struct sysref * sr)27410aa77c0SMatthew Dillon sysref_activate(struct sysref *sr)
27510aa77c0SMatthew Dillon {
27610aa77c0SMatthew Dillon 	int count;
27710aa77c0SMatthew Dillon 
27810aa77c0SMatthew Dillon 	for (;;) {
27910aa77c0SMatthew Dillon 		count = sr->refcnt;
2803c37c940SMatthew Dillon 		KASSERT(count < 0 && count + 0x40000001 > 0,
2813c37c940SMatthew Dillon 			("sysref_activate: bad count %08x", count));
28210aa77c0SMatthew Dillon 		if (atomic_cmpset_int(&sr->refcnt, count, count + 0x40000001))
28310aa77c0SMatthew Dillon 			break;
28410aa77c0SMatthew Dillon 		cpu_pause();
28510aa77c0SMatthew Dillon 	}
28610aa77c0SMatthew Dillon }
28710aa77c0SMatthew Dillon 
28810aa77c0SMatthew Dillon /*
28910aa77c0SMatthew Dillon  * Release a reference under special circumstances.  This call is made
29010aa77c0SMatthew Dillon  * from the sysref_put() inline from sys/sysref2.h for any 1->0 transitions,
29110aa77c0SMatthew Dillon  * negative->negative 'termination in progress' transitions, and when the
29210aa77c0SMatthew Dillon  * cmpset instruction fails during a normal transition.
29310aa77c0SMatthew Dillon  *
29410aa77c0SMatthew Dillon  * This function is called from the sysref_put() inline in sys/sysref2.h,
29510aa77c0SMatthew Dillon  * but handles all cases regardless.
29610aa77c0SMatthew Dillon  */
29710aa77c0SMatthew Dillon void
_sysref_put(struct sysref * sr)29810aa77c0SMatthew Dillon _sysref_put(struct sysref *sr)
29910aa77c0SMatthew Dillon {
30010aa77c0SMatthew Dillon 	int count;
30110aa77c0SMatthew Dillon 	void *data;
30210aa77c0SMatthew Dillon 
30318b4c2bbSMatthew Dillon 	KKASSERT((sr->flags & SRF_PUTAWAY) == 0);
30418b4c2bbSMatthew Dillon 
30510aa77c0SMatthew Dillon 	for (;;) {
30610aa77c0SMatthew Dillon 		count = sr->refcnt;
30710aa77c0SMatthew Dillon 		if (count > 1) {
30810aa77c0SMatthew Dillon 			/*
30910aa77c0SMatthew Dillon 			 * release 1 count, nominal case, active resource
31010aa77c0SMatthew Dillon 			 * structure, no other action required.
31110aa77c0SMatthew Dillon 			 */
31210aa77c0SMatthew Dillon 			if (atomic_cmpset_int(&sr->refcnt, count, count - 1))
31310aa77c0SMatthew Dillon 				break;
31410aa77c0SMatthew Dillon 		} else if (count == 1) {
31510aa77c0SMatthew Dillon 			/*
31610aa77c0SMatthew Dillon 			 * 1->0 transitions transition to -0x40000000 instead,
31710aa77c0SMatthew Dillon 			 * placing the resource structure into a termination-
31810aa77c0SMatthew Dillon 			 * in-progress state.  The termination function is
31910aa77c0SMatthew Dillon 			 * then called.
32010aa77c0SMatthew Dillon 			 */
321698331b0SMatthew Dillon 			data = (char *)sr - sr->srclass->offset;
322e654922cSMatthew Dillon 			sr->srclass->ops.lock(data);
323e654922cSMatthew Dillon 			if (atomic_cmpset_int(&sr->refcnt, count, -0x40000000)) {
324698331b0SMatthew Dillon 				sr->srclass->ops.terminate(data);
325*dd0e3cd7SMatthew Dillon 				/* callback unlocks */
32610aa77c0SMatthew Dillon 				break;
32710aa77c0SMatthew Dillon 			}
328e654922cSMatthew Dillon 			sr->srclass->ops.unlock(data);
32910aa77c0SMatthew Dillon 		} else if (count > -0x40000000) {
33010aa77c0SMatthew Dillon 			/*
33110aa77c0SMatthew Dillon 			 * release 1 count, nominal case, resource undergoing
33210aa77c0SMatthew Dillon 			 * termination.  The Resource can be ref'd and
33310aa77c0SMatthew Dillon 			 * deref'd while undergoing termination.
33410aa77c0SMatthew Dillon 			 */
33510aa77c0SMatthew Dillon 			if (atomic_cmpset_int(&sr->refcnt, count, count - 1))
33610aa77c0SMatthew Dillon 				break;
33710aa77c0SMatthew Dillon 		} else {
33810aa77c0SMatthew Dillon 			/*
33910aa77c0SMatthew Dillon 			 * Final release, set refcnt to 0.
34010aa77c0SMatthew Dillon 			 * Resource must have been allocated.
34110aa77c0SMatthew Dillon 			 *
34210aa77c0SMatthew Dillon 			 * If SRF_SYSIDUSED is not set just objcache_put() the
34310aa77c0SMatthew Dillon 			 * resource, otherwise objcache_dtor() the resource.
34410aa77c0SMatthew Dillon 			 */
34563f45d59SMatthew Dillon 			KKASSERT(count == -0x40000000);
34610aa77c0SMatthew Dillon 			if (atomic_cmpset_int(&sr->refcnt, count, 0)) {
34763f45d59SMatthew Dillon 				KKASSERT(sr->flags & SRF_ALLOCATED);
34818b4c2bbSMatthew Dillon 				sr->flags |= SRF_PUTAWAY;
349698331b0SMatthew Dillon 				data = (char *)sr - sr->srclass->offset;
35010aa77c0SMatthew Dillon 				if (sr->flags & SRF_SYSIDUSED)
351698331b0SMatthew Dillon 					objcache_dtor(sr->srclass->oc, data);
35210aa77c0SMatthew Dillon 				else
353698331b0SMatthew Dillon 					objcache_put(sr->srclass->oc, data);
35410aa77c0SMatthew Dillon 				break;
35510aa77c0SMatthew Dillon 			}
35610aa77c0SMatthew Dillon 		}
35710aa77c0SMatthew Dillon 		/* loop until the cmpset succeeds */
35810aa77c0SMatthew Dillon 		cpu_pause();
35910aa77c0SMatthew Dillon 	}
36010aa77c0SMatthew Dillon }
36110aa77c0SMatthew Dillon 
3623551ce6bSMatthew Dillon sysid_t
allocsysid(void)3633551ce6bSMatthew Dillon allocsysid(void)
3643551ce6bSMatthew Dillon {
3653551ce6bSMatthew Dillon 	globaldata_t gd = mycpu;
3663551ce6bSMatthew Dillon 	sysid_t sysid;
3673551ce6bSMatthew Dillon 
3683551ce6bSMatthew Dillon 	crit_enter_gd(gd);
3693551ce6bSMatthew Dillon 	gd->gd_sysid_alloc += ncpus_fit;
3703551ce6bSMatthew Dillon 	sysid = gd->gd_sysid_alloc;
3713551ce6bSMatthew Dillon 	crit_exit_gd(gd);
3723551ce6bSMatthew Dillon 	return(sysid);
3733551ce6bSMatthew Dillon }
3743551ce6bSMatthew Dillon 
375