Home | History | Annotate | Line # | Download | only in kern
subr_vmem.c revision 1.2.4.2
      1  1.2.4.2  gdamore /*	$NetBSD: subr_vmem.c,v 1.2.4.2 2006/07/13 17:49:51 gdamore Exp $	*/
      2  1.2.4.2  gdamore 
      3  1.2.4.2  gdamore /*-
      4  1.2.4.2  gdamore  * Copyright (c)2006 YAMAMOTO Takashi,
      5  1.2.4.2  gdamore  * All rights reserved.
      6  1.2.4.2  gdamore  *
      7  1.2.4.2  gdamore  * Redistribution and use in source and binary forms, with or without
      8  1.2.4.2  gdamore  * modification, are permitted provided that the following conditions
      9  1.2.4.2  gdamore  * are met:
     10  1.2.4.2  gdamore  * 1. Redistributions of source code must retain the above copyright
     11  1.2.4.2  gdamore  *    notice, this list of conditions and the following disclaimer.
     12  1.2.4.2  gdamore  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.2.4.2  gdamore  *    notice, this list of conditions and the following disclaimer in the
     14  1.2.4.2  gdamore  *    documentation and/or other materials provided with the distribution.
     15  1.2.4.2  gdamore  *
     16  1.2.4.2  gdamore  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  1.2.4.2  gdamore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  1.2.4.2  gdamore  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  1.2.4.2  gdamore  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  1.2.4.2  gdamore  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  1.2.4.2  gdamore  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  1.2.4.2  gdamore  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  1.2.4.2  gdamore  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  1.2.4.2  gdamore  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  1.2.4.2  gdamore  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  1.2.4.2  gdamore  * SUCH DAMAGE.
     27  1.2.4.2  gdamore  */
     28  1.2.4.2  gdamore 
     29  1.2.4.2  gdamore /*
     30  1.2.4.2  gdamore  * reference:
     31  1.2.4.2  gdamore  * -	Magazines and Vmem: Extending the Slab Allocator
     32  1.2.4.2  gdamore  *	to Many CPUs and Arbitrary Resources
     33  1.2.4.2  gdamore  *	http://www.usenix.org/event/usenix01/bonwick.html
     34  1.2.4.2  gdamore  *
     35  1.2.4.2  gdamore  * TODO:
     36  1.2.4.2  gdamore  * -	implement quantum cache
     37  1.2.4.2  gdamore  * -	implement vmem_xalloc/vmem_xfree
     38  1.2.4.2  gdamore  */
     39  1.2.4.2  gdamore 
     40  1.2.4.2  gdamore #include <sys/cdefs.h>
     41  1.2.4.2  gdamore __KERNEL_RCSID(0, "$NetBSD: subr_vmem.c,v 1.2.4.2 2006/07/13 17:49:51 gdamore Exp $");
     42  1.2.4.2  gdamore 
     43  1.2.4.2  gdamore #define	VMEM_DEBUG
     44  1.2.4.2  gdamore 
     45  1.2.4.2  gdamore #include <sys/param.h>
     46  1.2.4.2  gdamore #include <sys/hash.h>
     47  1.2.4.2  gdamore #include <sys/queue.h>
     48  1.2.4.2  gdamore 
     49  1.2.4.2  gdamore #if defined(_KERNEL)
     50  1.2.4.2  gdamore #include <sys/systm.h>
     51  1.2.4.2  gdamore #include <sys/lock.h>
     52  1.2.4.2  gdamore #include <sys/malloc.h>
     53  1.2.4.2  gdamore #include <sys/once.h>
     54  1.2.4.2  gdamore #include <sys/pool.h>
     55  1.2.4.2  gdamore #include <sys/vmem.h>
     56  1.2.4.2  gdamore #else /* defined(_KERNEL) */
     57  1.2.4.2  gdamore #include "../sys/vmem.h"
     58  1.2.4.2  gdamore #endif /* defined(_KERNEL) */
     59  1.2.4.2  gdamore 
     60  1.2.4.2  gdamore #if defined(_KERNEL)
     61  1.2.4.2  gdamore #define	SIMPLELOCK_DECL(name)	struct simplelock name
     62  1.2.4.2  gdamore #else /* defined(_KERNEL) */
     63  1.2.4.2  gdamore #include <errno.h>
     64  1.2.4.2  gdamore #include <assert.h>
     65  1.2.4.2  gdamore #include <stdlib.h>
     66  1.2.4.2  gdamore 
     67  1.2.4.2  gdamore #define	KASSERT(a)		assert(a)
     68  1.2.4.2  gdamore #define	SIMPLELOCK_DECL(name)	/* nothing */
     69  1.2.4.2  gdamore #define	LOCK_ASSERT(a)		/* nothing */
     70  1.2.4.2  gdamore #define	simple_lock_init(a)	/* nothing */
     71  1.2.4.2  gdamore #define	simple_lock(a)		/* nothing */
     72  1.2.4.2  gdamore #define	simple_unlock(a)	/* nothing */
     73  1.2.4.2  gdamore #endif /* defined(_KERNEL) */
     74  1.2.4.2  gdamore 
     75  1.2.4.2  gdamore struct vmem;
     76  1.2.4.2  gdamore struct vmem_btag;
     77  1.2.4.2  gdamore 
     78  1.2.4.2  gdamore #if defined(VMEM_DEBUG)
     79  1.2.4.2  gdamore void vmem_dump(const vmem_t *);
     80  1.2.4.2  gdamore #endif /* defined(VMEM_DEBUG) */
     81  1.2.4.2  gdamore 
     82  1.2.4.2  gdamore #define	VMEM_MAXORDER		20
     83  1.2.4.2  gdamore #define	VMEM_HASHSIZE_INIT	4096	/* XXX */
     84  1.2.4.2  gdamore 
     85  1.2.4.2  gdamore #define	VM_FITMASK	(VM_BESTFIT | VM_INSTANTFIT)
     86  1.2.4.2  gdamore 
     87  1.2.4.2  gdamore CIRCLEQ_HEAD(vmem_seglist, vmem_btag);
     88  1.2.4.2  gdamore LIST_HEAD(vmem_freelist, vmem_btag);
     89  1.2.4.2  gdamore LIST_HEAD(vmem_hashlist, vmem_btag);
     90  1.2.4.2  gdamore 
     91  1.2.4.2  gdamore /* vmem arena */
     92  1.2.4.2  gdamore struct vmem {
     93  1.2.4.2  gdamore 	SIMPLELOCK_DECL(vm_lock);
     94  1.2.4.2  gdamore 	vmem_addr_t (*vm_allocfn)(vmem_t *, vmem_size_t, vmem_size_t *,
     95  1.2.4.2  gdamore 	    vm_flag_t);
     96  1.2.4.2  gdamore 	void (*vm_freefn)(vmem_t *, vmem_addr_t, vmem_size_t);
     97  1.2.4.2  gdamore 	vmem_t *vm_source;
     98  1.2.4.2  gdamore 	struct vmem_seglist vm_seglist;
     99  1.2.4.2  gdamore 	struct vmem_freelist vm_freelist[VMEM_MAXORDER];
    100  1.2.4.2  gdamore 	size_t vm_hashsize;
    101  1.2.4.2  gdamore 	size_t vm_nbusytag;
    102  1.2.4.2  gdamore 	struct vmem_hashlist *vm_hashlist;
    103  1.2.4.2  gdamore 	size_t vm_qcache_max;
    104  1.2.4.2  gdamore 	size_t vm_quantum_mask;
    105  1.2.4.2  gdamore 	int vm_quantum_shift;
    106  1.2.4.2  gdamore 	/* XXX qcache */
    107  1.2.4.2  gdamore 	const char *vm_name;
    108  1.2.4.2  gdamore };
    109  1.2.4.2  gdamore 
    110  1.2.4.2  gdamore #define	VMEM_LOCK(vm)	simple_lock(&vm->vm_lock)
    111  1.2.4.2  gdamore #define	VMEM_UNLOCK(vm)	simple_unlock(&vm->vm_lock)
    112  1.2.4.2  gdamore #define	VMEM_LOCK_INIT(vm)	simple_lock_init(&vm->vm_lock);
    113  1.2.4.2  gdamore #define	VMEM_ASSERT_LOCKED(vm) \
    114  1.2.4.2  gdamore 	LOCK_ASSERT(simple_lock_held(&vm->vm_lock))
    115  1.2.4.2  gdamore #define	VMEM_ASSERT_UNLOCKED(vm) \
    116  1.2.4.2  gdamore 	LOCK_ASSERT(!simple_lock_held(&vm->vm_lock))
    117  1.2.4.2  gdamore 
    118  1.2.4.2  gdamore /* boundary tag */
    119  1.2.4.2  gdamore struct vmem_btag {
    120  1.2.4.2  gdamore 	CIRCLEQ_ENTRY(vmem_btag) bt_seglist;
    121  1.2.4.2  gdamore 	union {
    122  1.2.4.2  gdamore 		LIST_ENTRY(vmem_btag) u_freelist; /* BT_TYPE_FREE */
    123  1.2.4.2  gdamore 		LIST_ENTRY(vmem_btag) u_hashlist; /* BT_TYPE_BUSY */
    124  1.2.4.2  gdamore 	} bt_u;
    125  1.2.4.2  gdamore #define	bt_hashlist	bt_u.u_hashlist
    126  1.2.4.2  gdamore #define	bt_freelist	bt_u.u_freelist
    127  1.2.4.2  gdamore 	vmem_addr_t bt_start;
    128  1.2.4.2  gdamore 	vmem_size_t bt_size;
    129  1.2.4.2  gdamore 	int bt_type;
    130  1.2.4.2  gdamore };
    131  1.2.4.2  gdamore 
    132  1.2.4.2  gdamore #define	BT_TYPE_SPAN		1
    133  1.2.4.2  gdamore #define	BT_TYPE_SPAN_STATIC	2
    134  1.2.4.2  gdamore #define	BT_TYPE_FREE		3
    135  1.2.4.2  gdamore #define	BT_TYPE_BUSY		4
    136  1.2.4.2  gdamore #define	BT_ISSPAN_P(bt)	((bt)->bt_type <= BT_TYPE_SPAN_STATIC)
    137  1.2.4.2  gdamore 
    138  1.2.4.2  gdamore #define	BT_END(bt)	((bt)->bt_start + (bt)->bt_size)
    139  1.2.4.2  gdamore 
    140  1.2.4.2  gdamore typedef struct vmem_btag bt_t;
    141  1.2.4.2  gdamore 
    142  1.2.4.2  gdamore /* ---- misc */
    143  1.2.4.2  gdamore 
    144  1.2.4.2  gdamore static int
    145  1.2.4.2  gdamore calc_order(vmem_size_t size)
    146  1.2.4.2  gdamore {
    147  1.2.4.2  gdamore 	int i;
    148  1.2.4.2  gdamore 
    149  1.2.4.2  gdamore 	KASSERT(size != 0);
    150  1.2.4.2  gdamore 
    151  1.2.4.2  gdamore 	i = 0;
    152  1.2.4.2  gdamore 	while (1 << (i + 1) <= size) {
    153  1.2.4.2  gdamore 		i++;
    154  1.2.4.2  gdamore 	}
    155  1.2.4.2  gdamore 
    156  1.2.4.2  gdamore 	KASSERT(1 << i <= size);
    157  1.2.4.2  gdamore 	KASSERT(size < 1 << (i + 1));
    158  1.2.4.2  gdamore 
    159  1.2.4.2  gdamore 	return i;
    160  1.2.4.2  gdamore }
    161  1.2.4.2  gdamore 
    162  1.2.4.2  gdamore #if defined(_KERNEL)
    163  1.2.4.2  gdamore static MALLOC_DEFINE(M_VMEM, "vmem", "vmem");
    164  1.2.4.2  gdamore #endif /* defined(_KERNEL) */
    165  1.2.4.2  gdamore 
    166  1.2.4.2  gdamore static void *
    167  1.2.4.2  gdamore xmalloc(size_t sz, vm_flag_t flags)
    168  1.2.4.2  gdamore {
    169  1.2.4.2  gdamore 
    170  1.2.4.2  gdamore #if defined(_KERNEL)
    171  1.2.4.2  gdamore 	return malloc(sz, M_VMEM,
    172  1.2.4.2  gdamore 	    M_CANFAIL | ((flags & VM_SLEEP) ? M_WAITOK : M_NOWAIT));
    173  1.2.4.2  gdamore #else /* defined(_KERNEL) */
    174  1.2.4.2  gdamore 	return malloc(sz);
    175  1.2.4.2  gdamore #endif /* defined(_KERNEL) */
    176  1.2.4.2  gdamore }
    177  1.2.4.2  gdamore 
    178  1.2.4.2  gdamore static void
    179  1.2.4.2  gdamore xfree(void *p)
    180  1.2.4.2  gdamore {
    181  1.2.4.2  gdamore 
    182  1.2.4.2  gdamore #if defined(_KERNEL)
    183  1.2.4.2  gdamore 	return free(p, M_VMEM);
    184  1.2.4.2  gdamore #else /* defined(_KERNEL) */
    185  1.2.4.2  gdamore 	return free(p);
    186  1.2.4.2  gdamore #endif /* defined(_KERNEL) */
    187  1.2.4.2  gdamore }
    188  1.2.4.2  gdamore 
    189  1.2.4.2  gdamore /* ---- boundary tag */
    190  1.2.4.2  gdamore 
    191  1.2.4.2  gdamore #if defined(_KERNEL)
    192  1.2.4.2  gdamore static struct pool_cache bt_poolcache;
    193  1.2.4.2  gdamore static POOL_INIT(bt_pool, sizeof(bt_t), 0, 0, 0, "vmembtpl", NULL);
    194  1.2.4.2  gdamore #endif /* defined(_KERNEL) */
    195  1.2.4.2  gdamore 
    196  1.2.4.2  gdamore static bt_t *
    197  1.2.4.2  gdamore bt_alloc(vmem_t *vm, vm_flag_t flags)
    198  1.2.4.2  gdamore {
    199  1.2.4.2  gdamore 	bt_t *bt;
    200  1.2.4.2  gdamore 
    201  1.2.4.2  gdamore #if defined(_KERNEL)
    202  1.2.4.2  gdamore 	/* XXX bootstrap */
    203  1.2.4.2  gdamore 	bt = pool_cache_get(&bt_poolcache,
    204  1.2.4.2  gdamore 	    (flags & VM_SLEEP) != 0 ? PR_WAITOK : PR_NOWAIT);
    205  1.2.4.2  gdamore #else /* defined(_KERNEL) */
    206  1.2.4.2  gdamore 	bt = malloc(sizeof *bt);
    207  1.2.4.2  gdamore #endif /* defined(_KERNEL) */
    208  1.2.4.2  gdamore 
    209  1.2.4.2  gdamore 	return bt;
    210  1.2.4.2  gdamore }
    211  1.2.4.2  gdamore 
    212  1.2.4.2  gdamore static void
    213  1.2.4.2  gdamore bt_free(vmem_t *vm, bt_t *bt)
    214  1.2.4.2  gdamore {
    215  1.2.4.2  gdamore 
    216  1.2.4.2  gdamore #if defined(_KERNEL)
    217  1.2.4.2  gdamore 	/* XXX bootstrap */
    218  1.2.4.2  gdamore 	pool_cache_put(&bt_poolcache, bt);
    219  1.2.4.2  gdamore #else /* defined(_KERNEL) */
    220  1.2.4.2  gdamore 	free(bt);
    221  1.2.4.2  gdamore #endif /* defined(_KERNEL) */
    222  1.2.4.2  gdamore }
    223  1.2.4.2  gdamore 
    224  1.2.4.2  gdamore /*
    225  1.2.4.2  gdamore  * freelist[0] ... [1, 1]
    226  1.2.4.2  gdamore  * freelist[1] ... [2, 3]
    227  1.2.4.2  gdamore  * freelist[2] ... [4, 7]
    228  1.2.4.2  gdamore  * freelist[3] ... [8, 15]
    229  1.2.4.2  gdamore  *  :
    230  1.2.4.2  gdamore  * freelist[n] ... [(1 << n), (1 << (n + 1)) - 1]
    231  1.2.4.2  gdamore  *  :
    232  1.2.4.2  gdamore  */
    233  1.2.4.2  gdamore 
    234  1.2.4.2  gdamore static struct vmem_freelist *
    235  1.2.4.2  gdamore bt_freehead_tofree(vmem_t *vm, vmem_size_t size)
    236  1.2.4.2  gdamore {
    237  1.2.4.2  gdamore 	const vmem_size_t qsize = size >> vm->vm_quantum_shift;
    238  1.2.4.2  gdamore 	int idx;
    239  1.2.4.2  gdamore 
    240  1.2.4.2  gdamore 	KASSERT((size & vm->vm_quantum_mask) == 0);
    241  1.2.4.2  gdamore 	KASSERT(size != 0);
    242  1.2.4.2  gdamore 
    243  1.2.4.2  gdamore 	idx = calc_order(qsize);
    244  1.2.4.2  gdamore 	KASSERT(idx >= 0);
    245  1.2.4.2  gdamore 	KASSERT(idx < VMEM_MAXORDER);
    246  1.2.4.2  gdamore 
    247  1.2.4.2  gdamore 	return &vm->vm_freelist[idx];
    248  1.2.4.2  gdamore }
    249  1.2.4.2  gdamore 
    250  1.2.4.2  gdamore static struct vmem_freelist *
    251  1.2.4.2  gdamore bt_freehead_toalloc(vmem_t *vm, vmem_size_t size, vm_flag_t strat)
    252  1.2.4.2  gdamore {
    253  1.2.4.2  gdamore 	const vmem_size_t qsize = size >> vm->vm_quantum_shift;
    254  1.2.4.2  gdamore 	int idx;
    255  1.2.4.2  gdamore 
    256  1.2.4.2  gdamore 	KASSERT((size & vm->vm_quantum_mask) == 0);
    257  1.2.4.2  gdamore 	KASSERT(size != 0);
    258  1.2.4.2  gdamore 
    259  1.2.4.2  gdamore 	idx = calc_order(qsize);
    260  1.2.4.2  gdamore 	if (strat == VM_INSTANTFIT && 1 << idx != qsize) {
    261  1.2.4.2  gdamore 		idx++;
    262  1.2.4.2  gdamore 		/* check too large request? */
    263  1.2.4.2  gdamore 	}
    264  1.2.4.2  gdamore 	KASSERT(idx >= 0);
    265  1.2.4.2  gdamore 	KASSERT(idx < VMEM_MAXORDER);
    266  1.2.4.2  gdamore 
    267  1.2.4.2  gdamore 	return &vm->vm_freelist[idx];
    268  1.2.4.2  gdamore }
    269  1.2.4.2  gdamore 
    270  1.2.4.2  gdamore /* ---- boundary tag hash */
    271  1.2.4.2  gdamore 
    272  1.2.4.2  gdamore static struct vmem_hashlist *
    273  1.2.4.2  gdamore bt_hashhead(vmem_t *vm, vmem_addr_t addr)
    274  1.2.4.2  gdamore {
    275  1.2.4.2  gdamore 	struct vmem_hashlist *list;
    276  1.2.4.2  gdamore 	unsigned int hash;
    277  1.2.4.2  gdamore 
    278  1.2.4.2  gdamore 	hash = hash32_buf(&addr, sizeof(addr), HASH32_BUF_INIT);
    279  1.2.4.2  gdamore 	list = &vm->vm_hashlist[hash % vm->vm_hashsize];
    280  1.2.4.2  gdamore 
    281  1.2.4.2  gdamore 	return list;
    282  1.2.4.2  gdamore }
    283  1.2.4.2  gdamore 
    284  1.2.4.2  gdamore static bt_t *
    285  1.2.4.2  gdamore bt_lookupbusy(vmem_t *vm, vmem_addr_t addr)
    286  1.2.4.2  gdamore {
    287  1.2.4.2  gdamore 	struct vmem_hashlist *list;
    288  1.2.4.2  gdamore 	bt_t *bt;
    289  1.2.4.2  gdamore 
    290  1.2.4.2  gdamore 	list = bt_hashhead(vm, addr);
    291  1.2.4.2  gdamore 	LIST_FOREACH(bt, list, bt_hashlist) {
    292  1.2.4.2  gdamore 		if (bt->bt_start == addr) {
    293  1.2.4.2  gdamore 			break;
    294  1.2.4.2  gdamore 		}
    295  1.2.4.2  gdamore 	}
    296  1.2.4.2  gdamore 
    297  1.2.4.2  gdamore 	return bt;
    298  1.2.4.2  gdamore }
    299  1.2.4.2  gdamore 
    300  1.2.4.2  gdamore static void
    301  1.2.4.2  gdamore bt_rembusy(vmem_t *vm, bt_t *bt)
    302  1.2.4.2  gdamore {
    303  1.2.4.2  gdamore 
    304  1.2.4.2  gdamore 	KASSERT(vm->vm_nbusytag > 0);
    305  1.2.4.2  gdamore 	vm->vm_nbusytag--;
    306  1.2.4.2  gdamore 	LIST_REMOVE(bt, bt_hashlist);
    307  1.2.4.2  gdamore }
    308  1.2.4.2  gdamore 
    309  1.2.4.2  gdamore static void
    310  1.2.4.2  gdamore bt_insbusy(vmem_t *vm, bt_t *bt)
    311  1.2.4.2  gdamore {
    312  1.2.4.2  gdamore 	struct vmem_hashlist *list;
    313  1.2.4.2  gdamore 
    314  1.2.4.2  gdamore 	KASSERT(bt->bt_type == BT_TYPE_BUSY);
    315  1.2.4.2  gdamore 
    316  1.2.4.2  gdamore 	list = bt_hashhead(vm, bt->bt_start);
    317  1.2.4.2  gdamore 	LIST_INSERT_HEAD(list, bt, bt_hashlist);
    318  1.2.4.2  gdamore 	vm->vm_nbusytag++;
    319  1.2.4.2  gdamore }
    320  1.2.4.2  gdamore 
    321  1.2.4.2  gdamore /* ---- boundary tag list */
    322  1.2.4.2  gdamore 
    323  1.2.4.2  gdamore static void
    324  1.2.4.2  gdamore bt_remseg(vmem_t *vm, bt_t *bt)
    325  1.2.4.2  gdamore {
    326  1.2.4.2  gdamore 
    327  1.2.4.2  gdamore 	CIRCLEQ_REMOVE(&vm->vm_seglist, bt, bt_seglist);
    328  1.2.4.2  gdamore }
    329  1.2.4.2  gdamore 
    330  1.2.4.2  gdamore static void
    331  1.2.4.2  gdamore bt_insseg(vmem_t *vm, bt_t *bt, bt_t *prev)
    332  1.2.4.2  gdamore {
    333  1.2.4.2  gdamore 
    334  1.2.4.2  gdamore 	CIRCLEQ_INSERT_AFTER(&vm->vm_seglist, prev, bt, bt_seglist);
    335  1.2.4.2  gdamore }
    336  1.2.4.2  gdamore 
    337  1.2.4.2  gdamore static void
    338  1.2.4.2  gdamore bt_insseg_tail(vmem_t *vm, bt_t *bt)
    339  1.2.4.2  gdamore {
    340  1.2.4.2  gdamore 
    341  1.2.4.2  gdamore 	CIRCLEQ_INSERT_TAIL(&vm->vm_seglist, bt, bt_seglist);
    342  1.2.4.2  gdamore }
    343  1.2.4.2  gdamore 
    344  1.2.4.2  gdamore static void
    345  1.2.4.2  gdamore bt_remfree(vmem_t *vm, bt_t *bt)
    346  1.2.4.2  gdamore {
    347  1.2.4.2  gdamore 
    348  1.2.4.2  gdamore 	KASSERT(bt->bt_type == BT_TYPE_FREE);
    349  1.2.4.2  gdamore 
    350  1.2.4.2  gdamore 	LIST_REMOVE(bt, bt_freelist);
    351  1.2.4.2  gdamore }
    352  1.2.4.2  gdamore 
    353  1.2.4.2  gdamore static void
    354  1.2.4.2  gdamore bt_insfree(vmem_t *vm, bt_t *bt)
    355  1.2.4.2  gdamore {
    356  1.2.4.2  gdamore 	struct vmem_freelist *list;
    357  1.2.4.2  gdamore 
    358  1.2.4.2  gdamore 	list = bt_freehead_tofree(vm, bt->bt_size);
    359  1.2.4.2  gdamore 	LIST_INSERT_HEAD(list, bt, bt_freelist);
    360  1.2.4.2  gdamore }
    361  1.2.4.2  gdamore 
    362  1.2.4.2  gdamore /* ---- vmem internal functions */
    363  1.2.4.2  gdamore 
    364  1.2.4.2  gdamore #if defined(_KERNEL)
    365  1.2.4.2  gdamore static int
    366  1.2.4.2  gdamore vmem_init(void)
    367  1.2.4.2  gdamore {
    368  1.2.4.2  gdamore 
    369  1.2.4.2  gdamore 	pool_cache_init(&bt_poolcache, &bt_pool, NULL, NULL, NULL);
    370  1.2.4.2  gdamore 	return 0;
    371  1.2.4.2  gdamore }
    372  1.2.4.2  gdamore #endif /* defined(_KERNEL) */
    373  1.2.4.2  gdamore 
    374  1.2.4.2  gdamore static vmem_addr_t
    375  1.2.4.2  gdamore vmem_add1(vmem_t *vm, vmem_addr_t addr, vmem_size_t size, vm_flag_t flags,
    376  1.2.4.2  gdamore     int spanbttype)
    377  1.2.4.2  gdamore {
    378  1.2.4.2  gdamore 	bt_t *btspan;
    379  1.2.4.2  gdamore 	bt_t *btfree;
    380  1.2.4.2  gdamore 
    381  1.2.4.2  gdamore 	KASSERT((flags & (VM_SLEEP|VM_NOSLEEP)) != 0);
    382  1.2.4.2  gdamore 	KASSERT((~flags & (VM_SLEEP|VM_NOSLEEP)) != 0);
    383  1.2.4.2  gdamore 	VMEM_ASSERT_UNLOCKED(vm);
    384  1.2.4.2  gdamore 
    385  1.2.4.2  gdamore 	btspan = bt_alloc(vm, flags);
    386  1.2.4.2  gdamore 	if (btspan == NULL) {
    387  1.2.4.2  gdamore 		return VMEM_ADDR_NULL;
    388  1.2.4.2  gdamore 	}
    389  1.2.4.2  gdamore 	btfree = bt_alloc(vm, flags);
    390  1.2.4.2  gdamore 	if (btfree == NULL) {
    391  1.2.4.2  gdamore 		bt_free(vm, btspan);
    392  1.2.4.2  gdamore 		return VMEM_ADDR_NULL;
    393  1.2.4.2  gdamore 	}
    394  1.2.4.2  gdamore 
    395  1.2.4.2  gdamore 	btspan->bt_type = spanbttype;
    396  1.2.4.2  gdamore 	btspan->bt_start = addr;
    397  1.2.4.2  gdamore 	btspan->bt_size = size;
    398  1.2.4.2  gdamore 
    399  1.2.4.2  gdamore 	btfree->bt_type = BT_TYPE_FREE;
    400  1.2.4.2  gdamore 	btfree->bt_start = addr;
    401  1.2.4.2  gdamore 	btfree->bt_size = size;
    402  1.2.4.2  gdamore 
    403  1.2.4.2  gdamore 	VMEM_LOCK(vm);
    404  1.2.4.2  gdamore 	bt_insseg_tail(vm, btspan);
    405  1.2.4.2  gdamore 	bt_insseg(vm, btfree, btspan);
    406  1.2.4.2  gdamore 	bt_insfree(vm, btfree);
    407  1.2.4.2  gdamore 	VMEM_UNLOCK(vm);
    408  1.2.4.2  gdamore 
    409  1.2.4.2  gdamore 	return addr;
    410  1.2.4.2  gdamore }
    411  1.2.4.2  gdamore 
    412  1.2.4.2  gdamore static int
    413  1.2.4.2  gdamore vmem_import(vmem_t *vm, vmem_size_t size, vm_flag_t flags)
    414  1.2.4.2  gdamore {
    415  1.2.4.2  gdamore 	vmem_addr_t addr;
    416  1.2.4.2  gdamore 
    417  1.2.4.2  gdamore 	VMEM_ASSERT_UNLOCKED(vm);
    418  1.2.4.2  gdamore 
    419  1.2.4.2  gdamore 	if (vm->vm_allocfn == NULL) {
    420  1.2.4.2  gdamore 		return EINVAL;
    421  1.2.4.2  gdamore 	}
    422  1.2.4.2  gdamore 
    423  1.2.4.2  gdamore 	addr = (*vm->vm_allocfn)(vm->vm_source, size, &size, flags);
    424  1.2.4.2  gdamore 	if (addr == VMEM_ADDR_NULL) {
    425  1.2.4.2  gdamore 		return ENOMEM;
    426  1.2.4.2  gdamore 	}
    427  1.2.4.2  gdamore 
    428  1.2.4.2  gdamore 	if (vmem_add1(vm, addr, size, flags, BT_TYPE_SPAN) == VMEM_ADDR_NULL) {
    429  1.2.4.2  gdamore 		(*vm->vm_freefn)(vm->vm_source, addr, size);
    430  1.2.4.2  gdamore 		return ENOMEM;
    431  1.2.4.2  gdamore 	}
    432  1.2.4.2  gdamore 
    433  1.2.4.2  gdamore 	return 0;
    434  1.2.4.2  gdamore }
    435  1.2.4.2  gdamore 
    436  1.2.4.2  gdamore static int
    437  1.2.4.2  gdamore vmem_rehash(vmem_t *vm, size_t newhashsize, vm_flag_t flags)
    438  1.2.4.2  gdamore {
    439  1.2.4.2  gdamore 	bt_t *bt;
    440  1.2.4.2  gdamore 	int i;
    441  1.2.4.2  gdamore 	struct vmem_hashlist *newhashlist;
    442  1.2.4.2  gdamore 	struct vmem_hashlist *oldhashlist;
    443  1.2.4.2  gdamore 	size_t oldhashsize;
    444  1.2.4.2  gdamore 
    445  1.2.4.2  gdamore 	KASSERT(newhashsize > 0);
    446  1.2.4.2  gdamore 	VMEM_ASSERT_UNLOCKED(vm);
    447  1.2.4.2  gdamore 
    448  1.2.4.2  gdamore 	newhashlist =
    449  1.2.4.2  gdamore 	    xmalloc(sizeof(struct vmem_hashlist *) * newhashsize, flags);
    450  1.2.4.2  gdamore 	if (newhashlist == NULL) {
    451  1.2.4.2  gdamore 		return ENOMEM;
    452  1.2.4.2  gdamore 	}
    453  1.2.4.2  gdamore 	for (i = 0; i < newhashsize; i++) {
    454  1.2.4.2  gdamore 		LIST_INIT(&newhashlist[i]);
    455  1.2.4.2  gdamore 	}
    456  1.2.4.2  gdamore 
    457  1.2.4.2  gdamore 	VMEM_LOCK(vm);
    458  1.2.4.2  gdamore 	oldhashlist = vm->vm_hashlist;
    459  1.2.4.2  gdamore 	oldhashsize = vm->vm_hashsize;
    460  1.2.4.2  gdamore 	vm->vm_hashlist = newhashlist;
    461  1.2.4.2  gdamore 	vm->vm_hashsize = newhashsize;
    462  1.2.4.2  gdamore 	if (oldhashlist == NULL) {
    463  1.2.4.2  gdamore 		VMEM_UNLOCK(vm);
    464  1.2.4.2  gdamore 		return 0;
    465  1.2.4.2  gdamore 	}
    466  1.2.4.2  gdamore 	for (i = 0; i < oldhashsize; i++) {
    467  1.2.4.2  gdamore 		while ((bt = LIST_FIRST(&oldhashlist[i])) != NULL) {
    468  1.2.4.2  gdamore 			bt_rembusy(vm, bt); /* XXX */
    469  1.2.4.2  gdamore 			bt_insbusy(vm, bt);
    470  1.2.4.2  gdamore 		}
    471  1.2.4.2  gdamore 	}
    472  1.2.4.2  gdamore 	VMEM_UNLOCK(vm);
    473  1.2.4.2  gdamore 
    474  1.2.4.2  gdamore 	xfree(oldhashlist);
    475  1.2.4.2  gdamore 
    476  1.2.4.2  gdamore 	return 0;
    477  1.2.4.2  gdamore }
    478  1.2.4.2  gdamore 
    479  1.2.4.2  gdamore /* ---- vmem API */
    480  1.2.4.2  gdamore 
    481  1.2.4.2  gdamore /*
    482  1.2.4.2  gdamore  * vmem_create: create an arena.
    483  1.2.4.2  gdamore  *
    484  1.2.4.2  gdamore  * => must not be called from interrupt context.
    485  1.2.4.2  gdamore  */
    486  1.2.4.2  gdamore 
    487  1.2.4.2  gdamore vmem_t *
    488  1.2.4.2  gdamore vmem_create(const char *name, vmem_addr_t base, vmem_size_t size,
    489  1.2.4.2  gdamore     vmem_size_t quantum,
    490  1.2.4.2  gdamore     vmem_addr_t (*allocfn)(vmem_t *, vmem_size_t, vmem_size_t *, vm_flag_t),
    491  1.2.4.2  gdamore     void (*freefn)(vmem_t *, vmem_addr_t, vmem_size_t),
    492  1.2.4.2  gdamore     vmem_t *source, vmem_size_t qcache_max, vm_flag_t flags)
    493  1.2.4.2  gdamore {
    494  1.2.4.2  gdamore 	vmem_t *vm;
    495  1.2.4.2  gdamore 	int i;
    496  1.2.4.2  gdamore #if defined(_KERNEL)
    497  1.2.4.2  gdamore 	static ONCE_DECL(control);
    498  1.2.4.2  gdamore #endif /* defined(_KERNEL) */
    499  1.2.4.2  gdamore 
    500  1.2.4.2  gdamore 	KASSERT((flags & (VM_SLEEP|VM_NOSLEEP)) != 0);
    501  1.2.4.2  gdamore 	KASSERT((~flags & (VM_SLEEP|VM_NOSLEEP)) != 0);
    502  1.2.4.2  gdamore 
    503  1.2.4.2  gdamore #if defined(_KERNEL)
    504  1.2.4.2  gdamore 	if (RUN_ONCE(&control, vmem_init)) {
    505  1.2.4.2  gdamore 		return NULL;
    506  1.2.4.2  gdamore 	}
    507  1.2.4.2  gdamore #endif /* defined(_KERNEL) */
    508  1.2.4.2  gdamore 	vm = xmalloc(sizeof(*vm), flags);
    509  1.2.4.2  gdamore 	if (vm == NULL) {
    510  1.2.4.2  gdamore 		return NULL;
    511  1.2.4.2  gdamore 	}
    512  1.2.4.2  gdamore 
    513  1.2.4.2  gdamore 	VMEM_LOCK_INIT(vm);
    514  1.2.4.2  gdamore 	vm->vm_name = name;
    515  1.2.4.2  gdamore 	vm->vm_quantum_mask = quantum - 1;
    516  1.2.4.2  gdamore 	vm->vm_quantum_shift = calc_order(quantum);
    517  1.2.4.2  gdamore 	KASSERT((1 << vm->vm_quantum_shift) == quantum);
    518  1.2.4.2  gdamore 	vm->vm_allocfn = allocfn;
    519  1.2.4.2  gdamore 	vm->vm_freefn = freefn;
    520  1.2.4.2  gdamore 	vm->vm_source = source;
    521  1.2.4.2  gdamore 	vm->vm_qcache_max = qcache_max;
    522  1.2.4.2  gdamore 	vm->vm_nbusytag = 0;
    523  1.2.4.2  gdamore 
    524  1.2.4.2  gdamore 	CIRCLEQ_INIT(&vm->vm_seglist);
    525  1.2.4.2  gdamore 	for (i = 0; i < VMEM_MAXORDER; i++) {
    526  1.2.4.2  gdamore 		LIST_INIT(&vm->vm_freelist[i]);
    527  1.2.4.2  gdamore 	}
    528  1.2.4.2  gdamore 	vm->vm_hashlist = NULL;
    529  1.2.4.2  gdamore 	if (vmem_rehash(vm, VMEM_HASHSIZE_INIT, flags)) {
    530  1.2.4.2  gdamore 		vmem_destroy(vm);
    531  1.2.4.2  gdamore 		return NULL;
    532  1.2.4.2  gdamore 	}
    533  1.2.4.2  gdamore 
    534  1.2.4.2  gdamore 	if (size != 0) {
    535  1.2.4.2  gdamore 		if (vmem_add(vm, base, size, flags) == 0) {
    536  1.2.4.2  gdamore 			vmem_destroy(vm);
    537  1.2.4.2  gdamore 			return NULL;
    538  1.2.4.2  gdamore 		}
    539  1.2.4.2  gdamore 	}
    540  1.2.4.2  gdamore 
    541  1.2.4.2  gdamore 	return vm;
    542  1.2.4.2  gdamore }
    543  1.2.4.2  gdamore 
    544  1.2.4.2  gdamore void
    545  1.2.4.2  gdamore vmem_destroy(vmem_t *vm)
    546  1.2.4.2  gdamore {
    547  1.2.4.2  gdamore 
    548  1.2.4.2  gdamore 	VMEM_ASSERT_UNLOCKED(vm);
    549  1.2.4.2  gdamore 
    550  1.2.4.2  gdamore 	if (vm->vm_hashlist != NULL) {
    551  1.2.4.2  gdamore 		int i;
    552  1.2.4.2  gdamore 
    553  1.2.4.2  gdamore 		for (i = 0; i < vm->vm_hashsize; i++) {
    554  1.2.4.2  gdamore 			bt_t *bt;
    555  1.2.4.2  gdamore 
    556  1.2.4.2  gdamore 			while ((bt = LIST_FIRST(&vm->vm_hashlist[i])) != NULL) {
    557  1.2.4.2  gdamore 				KASSERT(bt->bt_type == BT_TYPE_SPAN_STATIC);
    558  1.2.4.2  gdamore 				bt_free(vm, bt);
    559  1.2.4.2  gdamore 			}
    560  1.2.4.2  gdamore 		}
    561  1.2.4.2  gdamore 		xfree(vm->vm_hashlist);
    562  1.2.4.2  gdamore 	}
    563  1.2.4.2  gdamore 	xfree(vm);
    564  1.2.4.2  gdamore }
    565  1.2.4.2  gdamore 
    566  1.2.4.2  gdamore vmem_size_t
    567  1.2.4.2  gdamore vmem_roundup_size(vmem_t *vm, vmem_size_t size)
    568  1.2.4.2  gdamore {
    569  1.2.4.2  gdamore 
    570  1.2.4.2  gdamore 	return (size + vm->vm_quantum_mask) & ~vm->vm_quantum_mask;
    571  1.2.4.2  gdamore }
    572  1.2.4.2  gdamore 
    573  1.2.4.2  gdamore /*
    574  1.2.4.2  gdamore  * vmem_alloc:
    575  1.2.4.2  gdamore  *
    576  1.2.4.2  gdamore  * => caller must ensure appropriate spl,
    577  1.2.4.2  gdamore  *    if the arena can be accessed from interrupt context.
    578  1.2.4.2  gdamore  */
    579  1.2.4.2  gdamore 
    580  1.2.4.2  gdamore vmem_addr_t
    581  1.2.4.2  gdamore vmem_alloc(vmem_t *vm, vmem_size_t size0, vm_flag_t flags)
    582  1.2.4.2  gdamore {
    583  1.2.4.2  gdamore 	struct vmem_freelist *list;
    584  1.2.4.2  gdamore 	struct vmem_freelist *first;
    585  1.2.4.2  gdamore 	struct vmem_freelist *end;
    586  1.2.4.2  gdamore 	bt_t *bt;
    587  1.2.4.2  gdamore 	bt_t *btnew;
    588  1.2.4.2  gdamore 	const vmem_size_t size = vmem_roundup_size(vm, size0);
    589  1.2.4.2  gdamore 	vm_flag_t strat = flags & VM_FITMASK;
    590  1.2.4.2  gdamore 
    591  1.2.4.2  gdamore 	KASSERT((flags & (VM_SLEEP|VM_NOSLEEP)) != 0);
    592  1.2.4.2  gdamore 	KASSERT((~flags & (VM_SLEEP|VM_NOSLEEP)) != 0);
    593  1.2.4.2  gdamore 	VMEM_ASSERT_UNLOCKED(vm);
    594  1.2.4.2  gdamore 
    595  1.2.4.2  gdamore 	KASSERT(size0 > 0);
    596  1.2.4.2  gdamore 	KASSERT(size > 0);
    597  1.2.4.2  gdamore 	KASSERT(strat == VM_BESTFIT || strat == VM_INSTANTFIT);
    598  1.2.4.2  gdamore 
    599  1.2.4.2  gdamore 	btnew = bt_alloc(vm, flags);
    600  1.2.4.2  gdamore 	if (btnew == NULL) {
    601  1.2.4.2  gdamore 		return VMEM_ADDR_NULL;
    602  1.2.4.2  gdamore 	}
    603  1.2.4.2  gdamore 
    604  1.2.4.2  gdamore retry_strat:
    605  1.2.4.2  gdamore 	first = bt_freehead_toalloc(vm, size, strat);
    606  1.2.4.2  gdamore 	end = &vm->vm_freelist[VMEM_MAXORDER];
    607  1.2.4.2  gdamore retry:
    608  1.2.4.2  gdamore 	bt = NULL;
    609  1.2.4.2  gdamore 	VMEM_LOCK(vm);
    610  1.2.4.2  gdamore 	if (strat == VM_INSTANTFIT) {
    611  1.2.4.2  gdamore 		for (list = first; list < end; list++) {
    612  1.2.4.2  gdamore 			bt = LIST_FIRST(list);
    613  1.2.4.2  gdamore 			if (bt != NULL) {
    614  1.2.4.2  gdamore 				goto gotit;
    615  1.2.4.2  gdamore 			}
    616  1.2.4.2  gdamore 		}
    617  1.2.4.2  gdamore 	} else { /* VM_BESTFIT */
    618  1.2.4.2  gdamore 		for (list = first; list < end; list++) {
    619  1.2.4.2  gdamore 			LIST_FOREACH(bt, list, bt_freelist) {
    620  1.2.4.2  gdamore 				if (bt->bt_size >= size) {
    621  1.2.4.2  gdamore 					goto gotit;
    622  1.2.4.2  gdamore 				}
    623  1.2.4.2  gdamore 			}
    624  1.2.4.2  gdamore 		}
    625  1.2.4.2  gdamore 	}
    626  1.2.4.2  gdamore 	VMEM_UNLOCK(vm);
    627  1.2.4.2  gdamore #if 1
    628  1.2.4.2  gdamore 	if (strat == VM_INSTANTFIT) {
    629  1.2.4.2  gdamore 		strat = VM_BESTFIT;
    630  1.2.4.2  gdamore 		goto retry_strat;
    631  1.2.4.2  gdamore 	}
    632  1.2.4.2  gdamore #endif
    633  1.2.4.2  gdamore 	if (vmem_import(vm, size, flags) == 0) {
    634  1.2.4.2  gdamore 		goto retry;
    635  1.2.4.2  gdamore 	}
    636  1.2.4.2  gdamore 	/* XXX */
    637  1.2.4.2  gdamore 	return VMEM_ADDR_NULL;
    638  1.2.4.2  gdamore 
    639  1.2.4.2  gdamore gotit:
    640  1.2.4.2  gdamore 	KASSERT(bt->bt_type == BT_TYPE_FREE);
    641  1.2.4.2  gdamore 	KASSERT(bt->bt_size >= size);
    642  1.2.4.2  gdamore 	bt_remfree(vm, bt);
    643  1.2.4.2  gdamore 	if (bt->bt_size != size && bt->bt_size - size > vm->vm_quantum_mask) {
    644  1.2.4.2  gdamore 		/* split */
    645  1.2.4.2  gdamore 		btnew->bt_type = BT_TYPE_BUSY;
    646  1.2.4.2  gdamore 		btnew->bt_start = bt->bt_start;
    647  1.2.4.2  gdamore 		btnew->bt_size = size;
    648  1.2.4.2  gdamore 		bt->bt_start = bt->bt_start + size;
    649  1.2.4.2  gdamore 		bt->bt_size -= size;
    650  1.2.4.2  gdamore 		bt_insfree(vm, bt);
    651  1.2.4.2  gdamore 		bt_insseg(vm, btnew, CIRCLEQ_PREV(bt, bt_seglist));
    652  1.2.4.2  gdamore 		bt_insbusy(vm, btnew);
    653  1.2.4.2  gdamore 		VMEM_UNLOCK(vm);
    654  1.2.4.2  gdamore 	} else {
    655  1.2.4.2  gdamore 		bt->bt_type = BT_TYPE_BUSY;
    656  1.2.4.2  gdamore 		bt_insbusy(vm, bt);
    657  1.2.4.2  gdamore 		VMEM_UNLOCK(vm);
    658  1.2.4.2  gdamore 		bt_free(vm, btnew);
    659  1.2.4.2  gdamore 		btnew = bt;
    660  1.2.4.2  gdamore 	}
    661  1.2.4.2  gdamore 	KASSERT(btnew->bt_size >= size);
    662  1.2.4.2  gdamore 	btnew->bt_type = BT_TYPE_BUSY;
    663  1.2.4.2  gdamore 
    664  1.2.4.2  gdamore 	return btnew->bt_start;
    665  1.2.4.2  gdamore }
    666  1.2.4.2  gdamore 
    667  1.2.4.2  gdamore /*
    668  1.2.4.2  gdamore  * vmem_free:
    669  1.2.4.2  gdamore  *
    670  1.2.4.2  gdamore  * => caller must ensure appropriate spl,
    671  1.2.4.2  gdamore  *    if the arena can be accessed from interrupt context.
    672  1.2.4.2  gdamore  */
    673  1.2.4.2  gdamore 
    674  1.2.4.2  gdamore void
    675  1.2.4.2  gdamore vmem_free(vmem_t *vm, vmem_addr_t addr, vmem_size_t size)
    676  1.2.4.2  gdamore {
    677  1.2.4.2  gdamore 	bt_t *bt;
    678  1.2.4.2  gdamore 	bt_t *t;
    679  1.2.4.2  gdamore 
    680  1.2.4.2  gdamore 	VMEM_ASSERT_UNLOCKED(vm);
    681  1.2.4.2  gdamore 
    682  1.2.4.2  gdamore 	KASSERT(addr != VMEM_ADDR_NULL);
    683  1.2.4.2  gdamore 	KASSERT(size > 0);
    684  1.2.4.2  gdamore 
    685  1.2.4.2  gdamore 	VMEM_LOCK(vm);
    686  1.2.4.2  gdamore 
    687  1.2.4.2  gdamore 	bt = bt_lookupbusy(vm, addr);
    688  1.2.4.2  gdamore 	KASSERT(bt != NULL);
    689  1.2.4.2  gdamore 	KASSERT(bt->bt_start == addr);
    690  1.2.4.2  gdamore 	KASSERT(bt->bt_size == vmem_roundup_size(vm, size) ||
    691  1.2.4.2  gdamore 	    bt->bt_size - vmem_roundup_size(vm, size) <= vm->vm_quantum_mask);
    692  1.2.4.2  gdamore 	KASSERT(bt->bt_type == BT_TYPE_BUSY);
    693  1.2.4.2  gdamore 	bt_rembusy(vm, bt);
    694  1.2.4.2  gdamore 	bt->bt_type = BT_TYPE_FREE;
    695  1.2.4.2  gdamore 
    696  1.2.4.2  gdamore 	/* coalesce */
    697  1.2.4.2  gdamore 	t = CIRCLEQ_NEXT(bt, bt_seglist);
    698  1.2.4.2  gdamore 	if (t != NULL && t->bt_type == BT_TYPE_FREE) {
    699  1.2.4.2  gdamore 		KASSERT(BT_END(bt) == t->bt_start);
    700  1.2.4.2  gdamore 		bt_remfree(vm, t);
    701  1.2.4.2  gdamore 		bt_remseg(vm, t);
    702  1.2.4.2  gdamore 		bt->bt_size += t->bt_size;
    703  1.2.4.2  gdamore 		bt_free(vm, t);
    704  1.2.4.2  gdamore 	}
    705  1.2.4.2  gdamore 	t = CIRCLEQ_PREV(bt, bt_seglist);
    706  1.2.4.2  gdamore 	if (t != NULL && t->bt_type == BT_TYPE_FREE) {
    707  1.2.4.2  gdamore 		KASSERT(BT_END(t) == bt->bt_start);
    708  1.2.4.2  gdamore 		bt_remfree(vm, t);
    709  1.2.4.2  gdamore 		bt_remseg(vm, t);
    710  1.2.4.2  gdamore 		bt->bt_size += t->bt_size;
    711  1.2.4.2  gdamore 		bt->bt_start = t->bt_start;
    712  1.2.4.2  gdamore 		bt_free(vm, t);
    713  1.2.4.2  gdamore 	}
    714  1.2.4.2  gdamore 
    715  1.2.4.2  gdamore 	t = CIRCLEQ_PREV(bt, bt_seglist);
    716  1.2.4.2  gdamore 	KASSERT(t != NULL);
    717  1.2.4.2  gdamore 	KASSERT(BT_ISSPAN_P(t) || t->bt_type == BT_TYPE_BUSY);
    718  1.2.4.2  gdamore 	if (vm->vm_freefn != NULL && t->bt_type == BT_TYPE_SPAN &&
    719  1.2.4.2  gdamore 	    t->bt_size == bt->bt_size) {
    720  1.2.4.2  gdamore 		vmem_addr_t spanaddr;
    721  1.2.4.2  gdamore 		vmem_size_t spansize;
    722  1.2.4.2  gdamore 
    723  1.2.4.2  gdamore 		KASSERT(t->bt_start == bt->bt_start);
    724  1.2.4.2  gdamore 		spanaddr = bt->bt_start;
    725  1.2.4.2  gdamore 		spansize = bt->bt_size;
    726  1.2.4.2  gdamore 		bt_remseg(vm, bt);
    727  1.2.4.2  gdamore 		bt_free(vm, bt);
    728  1.2.4.2  gdamore 		bt_remseg(vm, t);
    729  1.2.4.2  gdamore 		bt_free(vm, t);
    730  1.2.4.2  gdamore 		VMEM_UNLOCK(vm);
    731  1.2.4.2  gdamore 		(*vm->vm_freefn)(vm->vm_source, spanaddr, spansize);
    732  1.2.4.2  gdamore 	} else {
    733  1.2.4.2  gdamore 		bt_insfree(vm, bt);
    734  1.2.4.2  gdamore 		VMEM_UNLOCK(vm);
    735  1.2.4.2  gdamore 	}
    736  1.2.4.2  gdamore }
    737  1.2.4.2  gdamore 
    738  1.2.4.2  gdamore /*
    739  1.2.4.2  gdamore  * vmem_add:
    740  1.2.4.2  gdamore  *
    741  1.2.4.2  gdamore  * => caller must ensure appropriate spl,
    742  1.2.4.2  gdamore  *    if the arena can be accessed from interrupt context.
    743  1.2.4.2  gdamore  */
    744  1.2.4.2  gdamore 
    745  1.2.4.2  gdamore vmem_addr_t
    746  1.2.4.2  gdamore vmem_add(vmem_t *vm, vmem_addr_t addr, vmem_size_t size, vm_flag_t flags)
    747  1.2.4.2  gdamore {
    748  1.2.4.2  gdamore 
    749  1.2.4.2  gdamore 	return vmem_add1(vm, addr, size, flags, BT_TYPE_SPAN_STATIC);
    750  1.2.4.2  gdamore }
    751  1.2.4.2  gdamore 
    752  1.2.4.2  gdamore /* ---- debug */
    753  1.2.4.2  gdamore 
    754  1.2.4.2  gdamore #if defined(VMEM_DEBUG)
    755  1.2.4.2  gdamore 
    756  1.2.4.2  gdamore #if !defined(_KERNEL)
    757  1.2.4.2  gdamore #include <stdio.h>
    758  1.2.4.2  gdamore #endif /* !defined(_KERNEL) */
    759  1.2.4.2  gdamore 
    760  1.2.4.2  gdamore void bt_dump(const bt_t *);
    761  1.2.4.2  gdamore 
    762  1.2.4.2  gdamore void
    763  1.2.4.2  gdamore bt_dump(const bt_t *bt)
    764  1.2.4.2  gdamore {
    765  1.2.4.2  gdamore 
    766  1.2.4.2  gdamore 	printf("\t%p: %" PRIu64 ", %" PRIu64 ", %d\n",
    767  1.2.4.2  gdamore 	    bt, (uint64_t)bt->bt_start, (uint64_t)bt->bt_size,
    768  1.2.4.2  gdamore 	    bt->bt_type);
    769  1.2.4.2  gdamore }
    770  1.2.4.2  gdamore 
    771  1.2.4.2  gdamore void
    772  1.2.4.2  gdamore vmem_dump(const vmem_t *vm)
    773  1.2.4.2  gdamore {
    774  1.2.4.2  gdamore 	const bt_t *bt;
    775  1.2.4.2  gdamore 	int i;
    776  1.2.4.2  gdamore 
    777  1.2.4.2  gdamore 	printf("vmem %p '%s'\n", vm, vm->vm_name);
    778  1.2.4.2  gdamore 	CIRCLEQ_FOREACH(bt, &vm->vm_seglist, bt_seglist) {
    779  1.2.4.2  gdamore 		bt_dump(bt);
    780  1.2.4.2  gdamore 	}
    781  1.2.4.2  gdamore 
    782  1.2.4.2  gdamore 	for (i = 0; i < VMEM_MAXORDER; i++) {
    783  1.2.4.2  gdamore 		const struct vmem_freelist *fl = &vm->vm_freelist[i];
    784  1.2.4.2  gdamore 
    785  1.2.4.2  gdamore 		if (LIST_EMPTY(fl)) {
    786  1.2.4.2  gdamore 			continue;
    787  1.2.4.2  gdamore 		}
    788  1.2.4.2  gdamore 
    789  1.2.4.2  gdamore 		printf("freelist[%d]\n", i);
    790  1.2.4.2  gdamore 		LIST_FOREACH(bt, fl, bt_freelist) {
    791  1.2.4.2  gdamore 			bt_dump(bt);
    792  1.2.4.2  gdamore 			if (bt->bt_size) {
    793  1.2.4.2  gdamore 			}
    794  1.2.4.2  gdamore 		}
    795  1.2.4.2  gdamore 	}
    796  1.2.4.2  gdamore }
    797  1.2.4.2  gdamore 
    798  1.2.4.2  gdamore #if !defined(_KERNEL)
    799  1.2.4.2  gdamore 
    800  1.2.4.2  gdamore #include <stdlib.h>
    801  1.2.4.2  gdamore 
    802  1.2.4.2  gdamore int
    803  1.2.4.2  gdamore main()
    804  1.2.4.2  gdamore {
    805  1.2.4.2  gdamore 	vmem_t *vm;
    806  1.2.4.2  gdamore 	vmem_addr_t p;
    807  1.2.4.2  gdamore 	struct reg {
    808  1.2.4.2  gdamore 		vmem_addr_t p;
    809  1.2.4.2  gdamore 		vmem_size_t sz;
    810  1.2.4.2  gdamore 	} *reg = NULL;
    811  1.2.4.2  gdamore 	int nreg = 0;
    812  1.2.4.2  gdamore 	int nalloc = 0;
    813  1.2.4.2  gdamore 	int nfree = 0;
    814  1.2.4.2  gdamore 	vmem_size_t total = 0;
    815  1.2.4.2  gdamore #if 1
    816  1.2.4.2  gdamore 	vm_flag_t strat = VM_INSTANTFIT;
    817  1.2.4.2  gdamore #else
    818  1.2.4.2  gdamore 	vm_flag_t strat = VM_BESTFIT;
    819  1.2.4.2  gdamore #endif
    820  1.2.4.2  gdamore 
    821  1.2.4.2  gdamore 	vm = vmem_create("test", VMEM_ADDR_NULL, 0, 1,
    822  1.2.4.2  gdamore 	    NULL, NULL, NULL, 0, VM_NOSLEEP);
    823  1.2.4.2  gdamore 	if (vm == NULL) {
    824  1.2.4.2  gdamore 		printf("vmem_create\n");
    825  1.2.4.2  gdamore 		exit(EXIT_FAILURE);
    826  1.2.4.2  gdamore 	}
    827  1.2.4.2  gdamore 	vmem_dump(vm);
    828  1.2.4.2  gdamore 
    829  1.2.4.2  gdamore 	p = vmem_add(vm, 100, 200, VM_SLEEP);
    830  1.2.4.2  gdamore 	p = vmem_add(vm, 2000, 1, VM_SLEEP);
    831  1.2.4.2  gdamore 	p = vmem_add(vm, 40000, 0x10000000>>12, VM_SLEEP);
    832  1.2.4.2  gdamore 	p = vmem_add(vm, 10000, 10000, VM_SLEEP);
    833  1.2.4.2  gdamore 	p = vmem_add(vm, 500, 1000, VM_SLEEP);
    834  1.2.4.2  gdamore 	vmem_dump(vm);
    835  1.2.4.2  gdamore 	for (;;) {
    836  1.2.4.2  gdamore 		struct reg *r;
    837  1.2.4.2  gdamore 
    838  1.2.4.2  gdamore 		if (rand() % 100 > 40) {
    839  1.2.4.2  gdamore 			vmem_size_t sz = rand() % 500 + 1;
    840  1.2.4.2  gdamore 
    841  1.2.4.2  gdamore 			printf("=== alloc %" PRIu64 "\n", (uint64_t)sz);
    842  1.2.4.2  gdamore 			p = vmem_alloc(vm, sz, strat|VM_SLEEP);
    843  1.2.4.2  gdamore 			printf("-> %" PRIu64 "\n", (uint64_t)p);
    844  1.2.4.2  gdamore 			vmem_dump(vm);
    845  1.2.4.2  gdamore 			if (p == VMEM_ADDR_NULL) {
    846  1.2.4.2  gdamore 				break;
    847  1.2.4.2  gdamore 			}
    848  1.2.4.2  gdamore 			nreg++;
    849  1.2.4.2  gdamore 			reg = realloc(reg, sizeof(*reg) * nreg);
    850  1.2.4.2  gdamore 			r = &reg[nreg - 1];
    851  1.2.4.2  gdamore 			r->p = p;
    852  1.2.4.2  gdamore 			r->sz = sz;
    853  1.2.4.2  gdamore 			total += sz;
    854  1.2.4.2  gdamore 			nalloc++;
    855  1.2.4.2  gdamore 		} else if (nreg != 0) {
    856  1.2.4.2  gdamore 			r = &reg[rand() % nreg];
    857  1.2.4.2  gdamore 			printf("=== free %" PRIu64 ", %" PRIu64 "\n",
    858  1.2.4.2  gdamore 			    (uint64_t)r->p, (uint64_t)r->sz);
    859  1.2.4.2  gdamore 			vmem_free(vm, r->p, r->sz);
    860  1.2.4.2  gdamore 			total -= r->sz;
    861  1.2.4.2  gdamore 			vmem_dump(vm);
    862  1.2.4.2  gdamore 			*r = reg[nreg - 1];
    863  1.2.4.2  gdamore 			nreg--;
    864  1.2.4.2  gdamore 			nfree++;
    865  1.2.4.2  gdamore 		}
    866  1.2.4.2  gdamore 		printf("total=%" PRIu64 "\n", (uint64_t)total);
    867  1.2.4.2  gdamore 	}
    868  1.2.4.2  gdamore 	fprintf(stderr, "total=%" PRIu64 ", nalloc=%d, nfree=%d\n",
    869  1.2.4.2  gdamore 	    (uint64_t)total, nalloc, nfree);
    870  1.2.4.2  gdamore 	exit(EXIT_SUCCESS);
    871  1.2.4.2  gdamore }
    872  1.2.4.2  gdamore #endif /* !defined(_KERNEL) */
    873  1.2.4.2  gdamore #endif /* defined(VMEM_DEBUG) */
    874