Index: sys/vm/vm_radix.c =================================================================== --- sys/vm/vm_radix.c (revision 253502) +++ sys/vm/vm_radix.c (working copy) @@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -103,30 +104,22 @@ struct vm_radix_node { static uma_zone_t vm_radix_node_zone; /* - * Allocate a radix node. Pre-allocation should ensure that the request - * will always be satisfied. + * Allocate a radix node. */ static __inline struct vm_radix_node * vm_radix_node_get(vm_pindex_t owner, uint16_t count, uint16_t clevel) { struct vm_radix_node *rnode; + u_int i; - rnode = uma_zalloc(vm_radix_node_zone, M_NOWAIT); - - /* - * The required number of nodes should already be pre-allocated - * by vm_radix_prealloc(). However, UMA can hold a few nodes - * in per-CPU buckets, which will not be accessible by the - * current CPU. Thus, the allocation could return NULL when - * the pre-allocated pool is close to exhaustion. Anyway, - * in practice this should never occur because a new node - * is not always required for insert. Thus, the pre-allocated - * pool should have some extra pages that prevent this from - * becoming a problem. - */ + rnode = uma_zalloc(vm_radix_node_zone, M_NOWAIT | M_ZERO); if (rnode == NULL) - panic("%s: uma_zalloc() returned NULL for a new node", - __func__); + panic("a fess d mammt"); + for (i = 0; i < VM_RADIX_COUNT; i++) + KASSERT(rnode->rn_child[i] == NULL, + ("vm_radix_node_put: rnode %p has child %d %p", rnode, + slot, rnode->rn_child[i])); + CTR1(KTR_DEBUG, "rnode created: %p", rnode); rnode->rn_owner = owner; rnode->rn_count = count; rnode->rn_clev = clevel; @@ -140,6 +133,7 @@ static __inline void vm_radix_node_put(struct vm_radix_node *rnode) { + CTR1(KTR_DEBUG, "rnode destroying: %p", rnode); uma_zfree(vm_radix_node_zone, rnode); } @@ -269,6 +263,8 @@ vm_radix_reclaim_allnodes_int(struct vm_radix_node continue; if (!vm_radix_isleaf(rnode->rn_child[slot])) vm_radix_reclaim_allnodes_int(rnode->rn_child[slot]); + CTR1(KTR_DEBUG, "rnode %p child leaving %d %p", rnode, slot, + rnode->rn_child[slot]); rnode->rn_child[slot] = NULL; rnode->rn_count--; } @@ -291,48 +287,38 @@ vm_radix_node_zone_dtor(void *mem, int size __unus rnode->rn_count)); for (slot = 0; slot < VM_RADIX_COUNT; slot++) KASSERT(rnode->rn_child[slot] == NULL, - ("vm_radix_node_put: rnode %p has a child", rnode)); + ("vm_radix_node_put: rnode %p has child %d %p", rnode, + slot, rnode->rn_child[slot])); } #endif +#ifndef UMA_MD_SMALL_ALLOC /* - * Radix node zone initializer. + * Reserve the KVA necessary to satisfy the node allocation. + * This is mandatory in architectures not supporting direct + * mapping as they will need otherwise to carve into the kernel maps for + * every node allocation, resulting into deadlocks for consumers already + * working with kernel maps. */ -static int -vm_radix_node_zone_init(void *mem, int size __unused, int flags __unused) -{ - struct vm_radix_node *rnode; - - rnode = mem; - memset(rnode->rn_child, 0, sizeof(rnode->rn_child)); - return (0); -} - -/* - * Pre-allocate intermediate nodes from the UMA slab zone. - */ static void -vm_radix_prealloc(void *arg __unused) +vm_radix_reserve_kva(void *arg __unused) { - int nodes; /* * Calculate the number of reserved nodes, discounting the pages that * are needed to store them. */ - nodes = ((vm_paddr_t)cnt.v_page_count * PAGE_SIZE) / (PAGE_SIZE + - sizeof(struct vm_radix_node)); - if (!uma_zone_reserve_kva(vm_radix_node_zone, nodes)) + if (!uma_zone_reserve_kva(vm_radix_node_zone, + ((vm_paddr_t)cnt.v_page_count * PAGE_SIZE) / (PAGE_SIZE + + sizeof(struct vm_radix_node)))) panic("%s: unable to create new zone", __func__); - uma_prealloc(vm_radix_node_zone, nodes); } -SYSINIT(vm_radix_prealloc, SI_SUB_KMEM, SI_ORDER_SECOND, vm_radix_prealloc, - NULL); +SYSINIT(vm_radix_reserve_kva, SI_SUB_KMEM, SI_ORDER_SECOND, + vm_radix_reserve_kva, NULL); +#endif /* * Initialize the UMA slab zone. - * Until vm_radix_prealloc() is called, the zone will be served by the - * UMA boot-time pre-allocated pool of pages. */ void vm_radix_init(void) @@ -345,8 +331,7 @@ vm_radix_init(void) #else NULL, #endif - vm_radix_node_zone_init, NULL, VM_RADIX_PAD, UMA_ZONE_VM | - UMA_ZONE_NOFREE); + NULL, NULL, VM_RADIX_PAD, UMA_ZONE_VM); } /* @@ -387,6 +372,8 @@ vm_radix_insert(struct vm_radix *rtree, vm_page_t *parentp = tmp; vm_radix_addpage(tmp, index, clev, page); vm_radix_addpage(tmp, m->pindex, clev, m); + CTR4(KTR_DEBUG, "rnode %p added %p %p count %d", rnode, + page, m, rnode->rn_count); return; } else if (vm_radix_keybarr(rnode, index)) break; @@ -394,6 +381,8 @@ vm_radix_insert(struct vm_radix *rtree, vm_page_t if (rnode->rn_child[slot] == NULL) { rnode->rn_count++; vm_radix_addpage(rnode, index, rnode->rn_clev, page); + CTR4(KTR_DEBUG, "rnode %p added at %d %p count %d", + rnode, slot, page, rnode->rn_count); return; } parentp = &rnode->rn_child[slot]; @@ -413,6 +402,8 @@ vm_radix_insert(struct vm_radix *rtree, vm_page_t vm_radix_addpage(tmp, index, clev, page); slot = vm_radix_slot(newind, clev); tmp->rn_child[slot] = rnode; + CTR4(KTR_DEBUG, "rnode %p added %p %p count %d", tmp, page, rnode, + tmp->rn_count); } /* @@ -694,6 +685,9 @@ vm_radix_remove(struct vm_radix *rtree, vm_pindex_ m = vm_radix_topage(rnode->rn_child[slot]); if (m->pindex != index) panic("%s: invalid key found", __func__); + CTR4(KTR_DEBUG, "rnode %p removing at %d %p count %d", + rnode, slot, rnode->rn_child[slot], + rnode->rn_count); rnode->rn_child[slot] = NULL; rnode->rn_count--; if (rnode->rn_count > 1) @@ -711,6 +705,8 @@ vm_radix_remove(struct vm_radix *rtree, vm_pindex_ ("%s: invalid child value", __func__)); parent->rn_child[slot] = rnode->rn_child[i]; } + CTR4(KTR_DEBUG, "rnode %p removing at %d %p count %d", + rnode, i, rnode->rn_child[i], rnode->rn_count); rnode->rn_count--; rnode->rn_child[i] = NULL; vm_radix_node_put(rnode); Index: sys/vm/vm_page.c =================================================================== --- sys/vm/vm_page.c (revision 253502) +++ sys/vm/vm_page.c (working copy) @@ -316,7 +316,8 @@ vm_page_startup(vm_offset_t vaddr) /* * Initialize the page and queue locks. */ - mtx_init(&vm_page_queue_free_mtx, "vm page free queue", NULL, MTX_DEF); + mtx_init(&vm_page_queue_free_mtx, "vm page free queue", NULL, MTX_DEF | + MTX_RECURSE); for (i = 0; i < PA_LOCK_COUNT; i++) mtx_init(&pa_lock[i], "vm page", NULL, MTX_DEF); for (i = 0; i < PQ_COUNT; i++) Index: sys/sys/ktr.h =================================================================== --- sys/sys/ktr.h (revision 253502) +++ sys/sys/ktr.h (working copy) @@ -75,7 +75,8 @@ #define KTR_INET6 0x10000000 /* IPv6 stack */ #define KTR_SCHED 0x20000000 /* Machine parsed sched info. */ #define KTR_BUF 0x40000000 /* Buffer cache */ -#define KTR_ALL 0x7fffffff +#define KTR_DEBUG 0x80000000 +#define KTR_ALL 0xffffffff /* Trace classes to compile in */ #ifdef KTR