version 1.128.2.12, 2007/10/29 16:37:44 |
version 1.138.2.3, 2007/12/13 05:06:01 |
|
|
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
__KERNEL_RCSID(0, "$NetBSD$"); |
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#include "opt_ddb.h" |
#include "opt_pool.h" |
#include "opt_pool.h" |
#include "opt_poollog.h" |
#include "opt_poollog.h" |
#include "opt_lockdebug.h" |
#include "opt_lockdebug.h" |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
|
#include <sys/bitops.h> |
#include <sys/proc.h> |
#include <sys/proc.h> |
#include <sys/errno.h> |
#include <sys/errno.h> |
#include <sys/kernel.h> |
#include <sys/kernel.h> |
Line 56 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 58 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/debug.h> |
#include <sys/debug.h> |
#include <sys/lockdebug.h> |
#include <sys/lockdebug.h> |
#include <sys/xcall.h> |
#include <sys/xcall.h> |
|
#include <sys/cpu.h> |
|
|
#include <uvm/uvm.h> |
#include <uvm/uvm.h> |
|
|
Line 82 LIST_HEAD(,pool_cache) pool_cache_head = |
|
Line 85 LIST_HEAD(,pool_cache) pool_cache_head = |
|
/* Private pool for page header structures */ |
/* Private pool for page header structures */ |
#define PHPOOL_MAX 8 |
#define PHPOOL_MAX 8 |
static struct pool phpool[PHPOOL_MAX]; |
static struct pool phpool[PHPOOL_MAX]; |
#define PHPOOL_FREELIST_NELEM(idx) (((idx) == 0) ? 0 : (1 << (idx))) |
#define PHPOOL_FREELIST_NELEM(idx) \ |
|
(((idx) == 0) ? 0 : BITMAP_SIZE * (1 << (idx))) |
|
|
#ifdef POOL_SUBPAGE |
#ifdef POOL_SUBPAGE |
/* Pool of subpages for use by normal pools. */ |
/* Pool of subpages for use by normal pools. */ |
Line 98 static void pool_page_free_meta(struct p |
|
Line 102 static void pool_page_free_meta(struct p |
|
/* allocator for pool metadata */ |
/* allocator for pool metadata */ |
struct pool_allocator pool_allocator_meta = { |
struct pool_allocator pool_allocator_meta = { |
pool_page_alloc_meta, pool_page_free_meta, |
pool_page_alloc_meta, pool_page_free_meta, |
.pa_backingmapptr = &kmem_map, |
.pa_backingmapptr = &kernel_map, |
}; |
}; |
|
|
/* # of seconds to retain page after last use */ |
/* # of seconds to retain page after last use */ |
Line 111 static struct pool *drainpp; |
|
Line 115 static struct pool *drainpp; |
|
static kmutex_t pool_head_lock; |
static kmutex_t pool_head_lock; |
static kcondvar_t pool_busy; |
static kcondvar_t pool_busy; |
|
|
typedef uint8_t pool_item_freelist_t; |
typedef uint32_t pool_item_bitmap_t; |
|
#define BITMAP_SIZE (CHAR_BIT * sizeof(pool_item_bitmap_t)) |
|
#define BITMAP_MASK (BITMAP_SIZE - 1) |
|
|
struct pool_item_header { |
struct pool_item_header { |
/* Page headers */ |
/* Page headers */ |
Line 121 struct pool_item_header { |
|
Line 127 struct pool_item_header { |
|
ph_node; /* Off-page page headers */ |
ph_node; /* Off-page page headers */ |
void * ph_page; /* this page's address */ |
void * ph_page; /* this page's address */ |
struct timeval ph_time; /* last referenced */ |
struct timeval ph_time; /* last referenced */ |
|
uint16_t ph_nmissing; /* # of chunks in use */ |
|
uint16_t ph_off; /* start offset in page */ |
union { |
union { |
/* !PR_NOTOUCH */ |
/* !PR_NOTOUCH */ |
struct { |
struct { |
Line 129 struct pool_item_header { |
|
Line 137 struct pool_item_header { |
|
} phu_normal; |
} phu_normal; |
/* PR_NOTOUCH */ |
/* PR_NOTOUCH */ |
struct { |
struct { |
uint16_t |
pool_item_bitmap_t phu_bitmap[1]; |
phu_off; /* start offset in page */ |
|
pool_item_freelist_t |
|
phu_firstfree; /* first free item */ |
|
/* |
|
* XXX it might be better to use |
|
* a simple bitmap and ffs(3) |
|
*/ |
|
} phu_notouch; |
} phu_notouch; |
} ph_u; |
} ph_u; |
uint16_t ph_nmissing; /* # of chunks in use */ |
|
}; |
}; |
#define ph_itemlist ph_u.phu_normal.phu_itemlist |
#define ph_itemlist ph_u.phu_normal.phu_itemlist |
#define ph_off ph_u.phu_notouch.phu_off |
#define ph_bitmap ph_u.phu_notouch.phu_bitmap |
#define ph_firstfree ph_u.phu_notouch.phu_firstfree |
|
|
|
struct pool_item { |
struct pool_item { |
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
Line 329 pr_enter_check(struct pool *pp, void (*p |
|
Line 328 pr_enter_check(struct pool *pp, void (*p |
|
#define pr_enter_check(pp, pr) |
#define pr_enter_check(pp, pr) |
#endif /* POOL_DIAGNOSTIC */ |
#endif /* POOL_DIAGNOSTIC */ |
|
|
static inline int |
static inline unsigned int |
pr_item_notouch_index(const struct pool *pp, const struct pool_item_header *ph, |
pr_item_notouch_index(const struct pool *pp, const struct pool_item_header *ph, |
const void *v) |
const void *v) |
{ |
{ |
const char *cp = v; |
const char *cp = v; |
int idx; |
unsigned int idx; |
|
|
KASSERT(pp->pr_roflags & PR_NOTOUCH); |
KASSERT(pp->pr_roflags & PR_NOTOUCH); |
idx = (cp - (char *)ph->ph_page - ph->ph_off) / pp->pr_size; |
idx = (cp - (char *)ph->ph_page - ph->ph_off) / pp->pr_size; |
Line 342 pr_item_notouch_index(const struct pool |
|
Line 341 pr_item_notouch_index(const struct pool |
|
return idx; |
return idx; |
} |
} |
|
|
#define PR_FREELIST_ALIGN(p) \ |
|
roundup((uintptr_t)(p), sizeof(pool_item_freelist_t)) |
|
#define PR_FREELIST(ph) ((pool_item_freelist_t *)PR_FREELIST_ALIGN((ph) + 1)) |
|
#define PR_INDEX_USED ((pool_item_freelist_t)-1) |
|
#define PR_INDEX_EOL ((pool_item_freelist_t)-2) |
|
|
|
static inline void |
static inline void |
pr_item_notouch_put(const struct pool *pp, struct pool_item_header *ph, |
pr_item_notouch_put(const struct pool *pp, struct pool_item_header *ph, |
void *obj) |
void *obj) |
{ |
{ |
int idx = pr_item_notouch_index(pp, ph, obj); |
unsigned int idx = pr_item_notouch_index(pp, ph, obj); |
pool_item_freelist_t *freelist = PR_FREELIST(ph); |
pool_item_bitmap_t *bitmap = ph->ph_bitmap + (idx / BITMAP_SIZE); |
|
pool_item_bitmap_t mask = 1 << (idx & BITMAP_MASK); |
|
|
KASSERT(freelist[idx] == PR_INDEX_USED); |
KASSERT((*bitmap & mask) == 0); |
freelist[idx] = ph->ph_firstfree; |
*bitmap |= mask; |
ph->ph_firstfree = idx; |
|
} |
} |
|
|
static inline void * |
static inline void * |
pr_item_notouch_get(const struct pool *pp, struct pool_item_header *ph) |
pr_item_notouch_get(const struct pool *pp, struct pool_item_header *ph) |
{ |
{ |
int idx = ph->ph_firstfree; |
pool_item_bitmap_t *bitmap = ph->ph_bitmap; |
pool_item_freelist_t *freelist = PR_FREELIST(ph); |
unsigned int idx; |
|
int i; |
|
|
KASSERT(freelist[idx] != PR_INDEX_USED); |
for (i = 0; ; i++) { |
ph->ph_firstfree = freelist[idx]; |
int bit; |
freelist[idx] = PR_INDEX_USED; |
|
|
|
|
KASSERT((i * BITMAP_SIZE) < pp->pr_itemsperpage); |
|
bit = ffs32(bitmap[i]); |
|
if (bit) { |
|
pool_item_bitmap_t mask; |
|
|
|
bit--; |
|
idx = (i * BITMAP_SIZE) + bit; |
|
mask = 1 << bit; |
|
KASSERT((bitmap[i] & mask) != 0); |
|
bitmap[i] &= ~mask; |
|
break; |
|
} |
|
} |
|
KASSERT(idx < pp->pr_itemsperpage); |
return (char *)ph->ph_page + ph->ph_off + idx * pp->pr_size; |
return (char *)ph->ph_page + ph->ph_off + idx * pp->pr_size; |
} |
} |
|
|
|
static inline void |
|
pr_item_notouch_init(const struct pool *pp, struct pool_item_header *ph) |
|
{ |
|
pool_item_bitmap_t *bitmap = ph->ph_bitmap; |
|
const int n = howmany(pp->pr_itemsperpage, BITMAP_SIZE); |
|
int i; |
|
|
|
for (i = 0; i < n; i++) { |
|
bitmap[i] = (pool_item_bitmap_t)-1; |
|
} |
|
} |
|
|
static inline int |
static inline int |
phtree_compare(struct pool_item_header *a, struct pool_item_header *b) |
phtree_compare(struct pool_item_header *a, struct pool_item_header *b) |
{ |
{ |
Line 393 phtree_compare(struct pool_item_header * |
|
Line 412 phtree_compare(struct pool_item_header * |
|
SPLAY_PROTOTYPE(phtree, pool_item_header, ph_node, phtree_compare); |
SPLAY_PROTOTYPE(phtree, pool_item_header, ph_node, phtree_compare); |
SPLAY_GENERATE(phtree, pool_item_header, ph_node, phtree_compare); |
SPLAY_GENERATE(phtree, pool_item_header, ph_node, phtree_compare); |
|
|
|
static inline struct pool_item_header * |
|
pr_find_pagehead_noalign(struct pool *pp, void *v) |
|
{ |
|
struct pool_item_header *ph, tmp; |
|
|
|
tmp.ph_page = (void *)(uintptr_t)v; |
|
ph = SPLAY_FIND(phtree, &pp->pr_phtree, &tmp); |
|
if (ph == NULL) { |
|
ph = SPLAY_ROOT(&pp->pr_phtree); |
|
if (ph != NULL && phtree_compare(&tmp, ph) >= 0) { |
|
ph = SPLAY_NEXT(phtree, &pp->pr_phtree, ph); |
|
} |
|
KASSERT(ph == NULL || phtree_compare(&tmp, ph) < 0); |
|
} |
|
|
|
return ph; |
|
} |
|
|
/* |
/* |
* Return the pool page header based on item address. |
* Return the pool page header based on item address. |
*/ |
*/ |
Line 402 pr_find_pagehead(struct pool *pp, void * |
|
Line 439 pr_find_pagehead(struct pool *pp, void * |
|
struct pool_item_header *ph, tmp; |
struct pool_item_header *ph, tmp; |
|
|
if ((pp->pr_roflags & PR_NOALIGN) != 0) { |
if ((pp->pr_roflags & PR_NOALIGN) != 0) { |
tmp.ph_page = (void *)(uintptr_t)v; |
ph = pr_find_pagehead_noalign(pp, v); |
ph = SPLAY_FIND(phtree, &pp->pr_phtree, &tmp); |
|
if (ph == NULL) { |
|
ph = SPLAY_ROOT(&pp->pr_phtree); |
|
if (ph != NULL && phtree_compare(&tmp, ph) >= 0) { |
|
ph = SPLAY_NEXT(phtree, &pp->pr_phtree, ph); |
|
} |
|
KASSERT(ph == NULL || phtree_compare(&tmp, ph) < 0); |
|
} |
|
} else { |
} else { |
void *page = |
void *page = |
(void *)((uintptr_t)v & pp->pr_alloc->pa_pagemask); |
(void *)((uintptr_t)v & pp->pr_alloc->pa_pagemask); |
Line 602 pool_init(struct pool *pp, size_t size, |
|
Line 631 pool_init(struct pool *pp, size_t size, |
|
size_t trysize, phsize; |
size_t trysize, phsize; |
int off, slack; |
int off, slack; |
|
|
KASSERT((1UL << (CHAR_BIT * sizeof(pool_item_freelist_t))) - 2 >= |
|
PHPOOL_FREELIST_NELEM(PHPOOL_MAX - 1)); |
|
|
|
#ifdef DEBUG |
#ifdef DEBUG |
/* |
/* |
* Check that the pool hasn't already been initialised and |
* Check that the pool hasn't already been initialised and |
Line 774 pool_init(struct pool *pp, size_t size, |
|
Line 800 pool_init(struct pool *pp, size_t size, |
|
|
|
#ifdef POOL_DIAGNOSTIC |
#ifdef POOL_DIAGNOSTIC |
if (flags & PR_LOGGING) { |
if (flags & PR_LOGGING) { |
if (kmem_map == NULL || |
if (kernel_map == NULL || |
(pp->pr_log = malloc(pool_logsize * sizeof(struct pool_log), |
(pp->pr_log = malloc(pool_logsize * sizeof(struct pool_log), |
M_TEMP, M_NOWAIT)) == NULL) |
M_TEMP, M_NOWAIT)) == NULL) |
pp->pr_roflags &= ~PR_LOGGING; |
pp->pr_roflags &= ~PR_LOGGING; |
Line 786 pool_init(struct pool *pp, size_t size, |
|
Line 812 pool_init(struct pool *pp, size_t size, |
|
pp->pr_entered_file = NULL; |
pp->pr_entered_file = NULL; |
pp->pr_entered_line = 0; |
pp->pr_entered_line = 0; |
|
|
mutex_init(&pp->pr_lock, MUTEX_DEFAULT, ipl); |
/* |
|
* XXXAD hack to prevent IP input processing from blocking. |
|
*/ |
|
if (ipl == IPL_SOFTNET) { |
|
mutex_init(&pp->pr_lock, MUTEX_DEFAULT, IPL_VM); |
|
} else { |
|
mutex_init(&pp->pr_lock, MUTEX_DEFAULT, ipl); |
|
} |
cv_init(&pp->pr_cv, wchan); |
cv_init(&pp->pr_cv, wchan); |
pp->pr_ipl = ipl; |
pp->pr_ipl = ipl; |
|
|
Line 807 pool_init(struct pool *pp, size_t size, |
|
Line 840 pool_init(struct pool *pp, size_t size, |
|
"phpool-%d", nelem); |
"phpool-%d", nelem); |
sz = sizeof(struct pool_item_header); |
sz = sizeof(struct pool_item_header); |
if (nelem) { |
if (nelem) { |
sz = PR_FREELIST_ALIGN(sz) |
sz = offsetof(struct pool_item_header, |
+ nelem * sizeof(pool_item_freelist_t); |
ph_bitmap[howmany(nelem, BITMAP_SIZE)]); |
} |
} |
pool_init(&phpool[idx], sz, 0, 0, 0, |
pool_init(&phpool[idx], sz, 0, 0, 0, |
phpool_names[idx], &pool_allocator_meta, IPL_VM); |
phpool_names[idx], &pool_allocator_meta, IPL_VM); |
Line 1413 pool_prime_page(struct pool *pp, void *s |
|
Line 1446 pool_prime_page(struct pool *pp, void *s |
|
/* |
/* |
* Color this page. |
* Color this page. |
*/ |
*/ |
cp = (char *)cp + pp->pr_curcolor; |
ph->ph_off = pp->pr_curcolor; |
|
cp = (char *)cp + ph->ph_off; |
if ((pp->pr_curcolor += align) > pp->pr_maxcolor) |
if ((pp->pr_curcolor += align) > pp->pr_maxcolor) |
pp->pr_curcolor = 0; |
pp->pr_curcolor = 0; |
|
|
Line 1432 pool_prime_page(struct pool *pp, void *s |
|
Line 1466 pool_prime_page(struct pool *pp, void *s |
|
pp->pr_nitems += n; |
pp->pr_nitems += n; |
|
|
if (pp->pr_roflags & PR_NOTOUCH) { |
if (pp->pr_roflags & PR_NOTOUCH) { |
pool_item_freelist_t *freelist = PR_FREELIST(ph); |
pr_item_notouch_init(pp, ph); |
int i; |
|
|
|
ph->ph_off = (char *)cp - (char *)storage; |
|
ph->ph_firstfree = 0; |
|
for (i = 0; i < n - 1; i++) |
|
freelist[i] = i + 1; |
|
freelist[n - 1] = PR_INDEX_EOL; |
|
} else { |
} else { |
while (n--) { |
while (n--) { |
pi = (struct pool_item *)cp; |
pi = (struct pool_item *)cp; |
Line 1572 pool_reclaim(struct pool *pp) |
|
Line 1599 pool_reclaim(struct pool *pp) |
|
struct pool_item_header *ph, *phnext; |
struct pool_item_header *ph, *phnext; |
struct pool_pagelist pq; |
struct pool_pagelist pq; |
struct timeval curtime, diff; |
struct timeval curtime, diff; |
|
bool klock; |
|
int rv; |
|
|
if (pp->pr_drain_hook != NULL) { |
if (pp->pr_drain_hook != NULL) { |
/* |
/* |
Line 1580 pool_reclaim(struct pool *pp) |
|
Line 1609 pool_reclaim(struct pool *pp) |
|
(*pp->pr_drain_hook)(pp->pr_drain_hook_arg, PR_NOWAIT); |
(*pp->pr_drain_hook)(pp->pr_drain_hook_arg, PR_NOWAIT); |
} |
} |
|
|
|
/* |
|
* XXXSMP Because mutexes at IPL_SOFTXXX are still spinlocks, |
|
* and we are called from the pagedaemon without kernel_lock. |
|
* Does not apply to IPL_SOFTBIO. |
|
*/ |
|
if (pp->pr_ipl == IPL_SOFTNET || pp->pr_ipl == IPL_SOFTCLOCK || |
|
pp->pr_ipl == IPL_SOFTSERIAL) { |
|
KERNEL_LOCK(1, NULL); |
|
klock = true; |
|
} else |
|
klock = false; |
|
|
/* Reclaim items from the pool's cache (if any). */ |
/* Reclaim items from the pool's cache (if any). */ |
if (pp->pr_cache != NULL) |
if (pp->pr_cache != NULL) |
pool_cache_invalidate(pp->pr_cache); |
pool_cache_invalidate(pp->pr_cache); |
|
|
if (mutex_tryenter(&pp->pr_lock) == 0) |
if (mutex_tryenter(&pp->pr_lock) == 0) { |
|
if (klock) { |
|
KERNEL_UNLOCK_ONE(NULL); |
|
} |
return (0); |
return (0); |
|
} |
pr_enter(pp, file, line); |
pr_enter(pp, file, line); |
|
|
LIST_INIT(&pq); |
LIST_INIT(&pq); |
Line 1618 pool_reclaim(struct pool *pp) |
|
Line 1663 pool_reclaim(struct pool *pp) |
|
|
|
pr_leave(pp); |
pr_leave(pp); |
mutex_exit(&pp->pr_lock); |
mutex_exit(&pp->pr_lock); |
|
|
if (LIST_EMPTY(&pq)) |
if (LIST_EMPTY(&pq)) |
return 0; |
rv = 0; |
|
else { |
|
pr_pagelist_free(pp, &pq); |
|
rv = 1; |
|
} |
|
|
pr_pagelist_free(pp, &pq); |
if (klock) { |
|
KERNEL_UNLOCK_ONE(NULL); |
|
} |
|
|
return (1); |
return (rv); |
} |
} |
|
|
/* |
/* |
Line 2006 pool_cache_bootstrap(pool_cache_t pc, si |
|
Line 2058 pool_cache_bootstrap(pool_cache_t pc, si |
|
palloc = &pool_allocator_nointr; |
palloc = &pool_allocator_nointr; |
pool_init(pp, size, align, align_offset, flags, wchan, palloc, ipl); |
pool_init(pp, size, align, align_offset, flags, wchan, palloc, ipl); |
|
|
mutex_init(&pc->pc_lock, MUTEX_DEFAULT, pp->pr_ipl); |
/* |
|
* XXXAD hack to prevent IP input processing from blocking. |
|
*/ |
|
if (ipl == IPL_SOFTNET) { |
|
mutex_init(&pc->pc_lock, MUTEX_DEFAULT, IPL_VM); |
|
} else { |
|
mutex_init(&pc->pc_lock, MUTEX_DEFAULT, ipl); |
|
} |
|
|
if (ctor == NULL) { |
if (ctor == NULL) { |
ctor = (int (*)(void *, void *, int))nullop; |
ctor = (int (*)(void *, void *, int))nullop; |
Line 2028 pool_cache_bootstrap(pool_cache_t pc, si |
|
Line 2087 pool_cache_bootstrap(pool_cache_t pc, si |
|
pc->pc_nfull = 0; |
pc->pc_nfull = 0; |
pc->pc_contended = 0; |
pc->pc_contended = 0; |
pc->pc_refcnt = 0; |
pc->pc_refcnt = 0; |
|
pc->pc_freecheck = NULL; |
|
|
/* Allocate per-CPU caches. */ |
/* Allocate per-CPU caches. */ |
memset(pc->pc_cpus, 0, sizeof(pc->pc_cpus)); |
memset(pc->pc_cpus, 0, sizeof(pc->pc_cpus)); |
pc->pc_ncpu = 0; |
pc->pc_ncpu = 0; |
for (CPU_INFO_FOREACH(cii, ci)) { |
if (ncpu < 2) { |
pool_cache_cpu_init1(ci, pc); |
/* XXX For sparc: boot CPU is not attached yet. */ |
|
pool_cache_cpu_init1(curcpu(), pc); |
|
} else { |
|
for (CPU_INFO_FOREACH(cii, ci)) { |
|
pool_cache_cpu_init1(ci, pc); |
|
} |
} |
} |
|
|
if (__predict_true(!cold)) { |
if (__predict_true(!cold)) { |
Line 2057 pool_cache_bootstrap(pool_cache_t pc, si |
|
Line 2122 pool_cache_bootstrap(pool_cache_t pc, si |
|
void |
void |
pool_cache_destroy(pool_cache_t pc) |
pool_cache_destroy(pool_cache_t pc) |
{ |
{ |
|
|
|
pool_cache_bootstrap_destroy(pc); |
|
pool_put(&cache_pool, pc); |
|
} |
|
|
|
/* |
|
* pool_cache_bootstrap_destroy: |
|
* |
|
* Kernel-private version of pool_cache_destroy(). |
|
* Destroy a pool cache initialized by pool_cache_bootstrap. |
|
*/ |
|
void |
|
pool_cache_bootstrap_destroy(pool_cache_t pc) |
|
{ |
struct pool *pp = &pc->pc_pool; |
struct pool *pp = &pc->pc_pool; |
pool_cache_cpu_t *cc; |
pool_cache_cpu_t *cc; |
pcg_t *pcg; |
pcg_t *pcg; |
Line 2096 pool_cache_destroy(pool_cache_t pc) |
|
Line 2175 pool_cache_destroy(pool_cache_t pc) |
|
/* Finally, destroy it. */ |
/* Finally, destroy it. */ |
mutex_destroy(&pc->pc_lock); |
mutex_destroy(&pc->pc_lock); |
pool_destroy(pp); |
pool_destroy(pp); |
pool_put(&cache_pool, pc); |
|
} |
} |
|
|
/* |
/* |
|
|
pool_cache_cpu_init1(struct cpu_info *ci, pool_cache_t pc) |
pool_cache_cpu_init1(struct cpu_info *ci, pool_cache_t pc) |
{ |
{ |
pool_cache_cpu_t *cc; |
pool_cache_cpu_t *cc; |
|
int index; |
|
|
|
index = ci->ci_index; |
|
|
|
KASSERT(index < MAXCPUS); |
KASSERT(((uintptr_t)pc->pc_cpus & (CACHE_LINE_SIZE - 1)) == 0); |
KASSERT(((uintptr_t)pc->pc_cpus & (CACHE_LINE_SIZE - 1)) == 0); |
|
|
if ((cc = pc->pc_cpus[ci->ci_index]) != NULL) { |
if ((cc = pc->pc_cpus[index]) != NULL) { |
KASSERT(cc->cc_cpu = ci); |
KASSERT(cc->cc_cpuindex == index); |
return; |
return; |
} |
} |
|
|
Line 2133 pool_cache_cpu_init1(struct cpu_info *ci |
|
Line 2215 pool_cache_cpu_init1(struct cpu_info *ci |
|
cc->cc_ipl = pc->pc_pool.pr_ipl; |
cc->cc_ipl = pc->pc_pool.pr_ipl; |
cc->cc_iplcookie = makeiplcookie(cc->cc_ipl); |
cc->cc_iplcookie = makeiplcookie(cc->cc_ipl); |
cc->cc_cache = pc; |
cc->cc_cache = pc; |
cc->cc_cpu = ci; |
cc->cc_cpuindex = index; |
cc->cc_hits = 0; |
cc->cc_hits = 0; |
cc->cc_misses = 0; |
cc->cc_misses = 0; |
cc->cc_current = NULL; |
cc->cc_current = NULL; |
cc->cc_previous = NULL; |
cc->cc_previous = NULL; |
|
|
pc->pc_cpus[ci->ci_index] = cc; |
pc->pc_cpus[index] = cc; |
} |
} |
|
|
/* |
/* |
Line 2178 pool_cache_reclaim(pool_cache_t pc) |
|
Line 2260 pool_cache_reclaim(pool_cache_t pc) |
|
return pool_reclaim(&pc->pc_pool); |
return pool_reclaim(&pc->pc_pool); |
} |
} |
|
|
|
static void |
|
pool_cache_destruct_object1(pool_cache_t pc, void *object) |
|
{ |
|
|
|
(*pc->pc_dtor)(pc->pc_arg, object); |
|
pool_put(&pc->pc_pool, object); |
|
} |
|
|
/* |
/* |
* pool_cache_destruct_object: |
* pool_cache_destruct_object: |
* |
* |
|
|
pool_cache_destruct_object(pool_cache_t pc, void *object) |
pool_cache_destruct_object(pool_cache_t pc, void *object) |
{ |
{ |
|
|
(*pc->pc_dtor)(pc->pc_arg, object); |
FREECHECK_IN(&pc->pc_freecheck, object); |
pool_put(&pc->pc_pool, object); |
|
|
pool_cache_destruct_object1(pc, object); |
} |
} |
|
|
/* |
/* |
Line 2209 pool_cache_invalidate_groups(pool_cache_ |
|
Line 2300 pool_cache_invalidate_groups(pool_cache_ |
|
|
|
for (i = 0; i < pcg->pcg_avail; i++) { |
for (i = 0; i < pcg->pcg_avail; i++) { |
object = pcg->pcg_objects[i].pcgo_va; |
object = pcg->pcg_objects[i].pcgo_va; |
pool_cache_destruct_object(pc, object); |
pool_cache_destruct_object1(pc, object); |
} |
} |
|
|
pool_put(&pcgpool, pcg); |
pool_put(&pcgpool, pcg); |
Line 2276 static inline pool_cache_cpu_t * |
|
Line 2367 static inline pool_cache_cpu_t * |
|
pool_cache_cpu_enter(pool_cache_t pc, int *s) |
pool_cache_cpu_enter(pool_cache_t pc, int *s) |
{ |
{ |
pool_cache_cpu_t *cc; |
pool_cache_cpu_t *cc; |
struct cpu_info *ci; |
|
|
|
/* |
/* |
* Prevent other users of the cache from accessing our |
* Prevent other users of the cache from accessing our |
* CPU-local data. To avoid touching shared state, we |
* CPU-local data. To avoid touching shared state, we |
* pull the neccessary information from CPU local data. |
* pull the neccessary information from CPU local data. |
*/ |
*/ |
ci = curcpu(); |
crit_enter(); |
KASSERT(ci->ci_data.cpu_index < MAXCPUS); |
cc = pc->pc_cpus[curcpu()->ci_index]; |
cc = pc->pc_cpus[ci->ci_data.cpu_index]; |
|
KASSERT(cc->cc_cache == pc); |
KASSERT(cc->cc_cache == pc); |
if (cc->cc_ipl == IPL_NONE) { |
if (cc->cc_ipl != IPL_NONE) { |
crit_enter(); |
|
} else { |
|
*s = splraiseipl(cc->cc_iplcookie); |
*s = splraiseipl(cc->cc_iplcookie); |
} |
} |
|
|
/* Moved to another CPU before disabling preemption? */ |
|
if (__predict_false(ci != curcpu())) { |
|
ci = curcpu(); |
|
cc = pc->pc_cpus[ci->ci_data.cpu_index]; |
|
} |
|
|
|
#ifdef DIAGNOSTIC |
|
KASSERT(cc->cc_cpu == ci); |
|
KASSERT(((uintptr_t)cc & (CACHE_LINE_SIZE - 1)) == 0); |
KASSERT(((uintptr_t)cc & (CACHE_LINE_SIZE - 1)) == 0); |
#endif |
|
|
|
return cc; |
return cc; |
} |
} |
Line 2312 pool_cache_cpu_exit(pool_cache_cpu_t *cc |
|
Line 2389 pool_cache_cpu_exit(pool_cache_cpu_t *cc |
|
{ |
{ |
|
|
/* No longer need exclusive access to the per-CPU data. */ |
/* No longer need exclusive access to the per-CPU data. */ |
if (cc->cc_ipl == IPL_NONE) { |
if (cc->cc_ipl != IPL_NONE) { |
crit_exit(); |
|
} else { |
|
splx(*s); |
splx(*s); |
} |
} |
|
crit_exit(); |
} |
} |
|
|
#if __GNUC_PREREQ__(3, 0) |
#if __GNUC_PREREQ__(3, 0) |
Line 2631 pool_cache_xcall(pool_cache_t pc) |
|
Line 2707 pool_cache_xcall(pool_cache_t pc) |
|
cc->cc_previous = NULL; |
cc->cc_previous = NULL; |
pool_cache_cpu_exit(cc, &s); |
pool_cache_cpu_exit(cc, &s); |
|
|
|
/* |
|
* XXXSMP Go to splvm to prevent kernel_lock from being taken, |
|
* because locks at IPL_SOFTXXX are still spinlocks. Does not |
|
* apply to IPL_SOFTBIO. Cross-call threads do not take the |
|
* kernel_lock. |
|
*/ |
|
s = splvm(); |
mutex_enter(&pc->pc_lock); |
mutex_enter(&pc->pc_lock); |
if (cur != NULL) { |
if (cur != NULL) { |
if (cur->pcg_avail == PCG_NOBJECTS) { |
if (cur->pcg_avail == PCG_NOBJECTS) { |
Line 2661 pool_cache_xcall(pool_cache_t pc) |
|
Line 2744 pool_cache_xcall(pool_cache_t pc) |
|
*list = prev; |
*list = prev; |
} |
} |
mutex_exit(&pc->pc_lock); |
mutex_exit(&pc->pc_lock); |
|
splx(s); |
} |
} |
|
|
/* |
/* |
Line 2682 void pool_page_free(struct pool *, void |
|
Line 2766 void pool_page_free(struct pool *, void |
|
#ifdef POOL_SUBPAGE |
#ifdef POOL_SUBPAGE |
struct pool_allocator pool_allocator_kmem_fullpage = { |
struct pool_allocator pool_allocator_kmem_fullpage = { |
pool_page_alloc, pool_page_free, 0, |
pool_page_alloc, pool_page_free, 0, |
.pa_backingmapptr = &kmem_map, |
.pa_backingmapptr = &kernel_map, |
}; |
}; |
#else |
#else |
struct pool_allocator pool_allocator_kmem = { |
struct pool_allocator pool_allocator_kmem = { |
pool_page_alloc, pool_page_free, 0, |
pool_page_alloc, pool_page_free, 0, |
.pa_backingmapptr = &kmem_map, |
.pa_backingmapptr = &kernel_map, |
}; |
}; |
#endif |
#endif |
|
|
Line 2712 void pool_subpage_free(struct pool *, vo |
|
Line 2796 void pool_subpage_free(struct pool *, vo |
|
|
|
struct pool_allocator pool_allocator_kmem = { |
struct pool_allocator pool_allocator_kmem = { |
pool_subpage_alloc, pool_subpage_free, POOL_SUBPAGE, |
pool_subpage_alloc, pool_subpage_free, POOL_SUBPAGE, |
.pa_backingmapptr = &kmem_map, |
.pa_backingmapptr = &kernel_map, |
}; |
}; |
|
|
void *pool_subpage_alloc_nointr(struct pool *, int); |
void *pool_subpage_alloc_nointr(struct pool *, int); |
Line 2720 void pool_subpage_free_nointr(struct poo |
|
Line 2804 void pool_subpage_free_nointr(struct poo |
|
|
|
struct pool_allocator pool_allocator_nointr = { |
struct pool_allocator pool_allocator_nointr = { |
pool_subpage_alloc, pool_subpage_free, POOL_SUBPAGE, |
pool_subpage_alloc, pool_subpage_free, POOL_SUBPAGE, |
.pa_backingmapptr = &kmem_map, |
.pa_backingmapptr = &kernel_map, |
}; |
}; |
#endif /* POOL_SUBPAGE */ |
#endif /* POOL_SUBPAGE */ |
|
|
Line 2758 pool_page_alloc(struct pool *pp, int fla |
|
Line 2842 pool_page_alloc(struct pool *pp, int fla |
|
{ |
{ |
bool waitok = (flags & PR_WAITOK) ? true : false; |
bool waitok = (flags & PR_WAITOK) ? true : false; |
|
|
return ((void *) uvm_km_alloc_poolpage_cache(kmem_map, waitok)); |
return ((void *) uvm_km_alloc_poolpage_cache(kernel_map, waitok)); |
} |
} |
|
|
void |
void |
pool_page_free(struct pool *pp, void *v) |
pool_page_free(struct pool *pp, void *v) |
{ |
{ |
|
|
uvm_km_free_poolpage_cache(kmem_map, (vaddr_t) v); |
uvm_km_free_poolpage_cache(kernel_map, (vaddr_t) v); |
} |
} |
|
|
static void * |
static void * |
Line 2773 pool_page_alloc_meta(struct pool *pp, in |
|
Line 2857 pool_page_alloc_meta(struct pool *pp, in |
|
{ |
{ |
bool waitok = (flags & PR_WAITOK) ? true : false; |
bool waitok = (flags & PR_WAITOK) ? true : false; |
|
|
return ((void *) uvm_km_alloc_poolpage(kmem_map, waitok)); |
return ((void *) uvm_km_alloc_poolpage(kernel_map, waitok)); |
} |
} |
|
|
static void |
static void |
pool_page_free_meta(struct pool *pp, void *v) |
pool_page_free_meta(struct pool *pp, void *v) |
{ |
{ |
|
|
uvm_km_free_poolpage(kmem_map, (vaddr_t) v); |
uvm_km_free_poolpage(kernel_map, (vaddr_t) v); |
} |
} |
|
|
#ifdef POOL_SUBPAGE |
#ifdef POOL_SUBPAGE |
Line 2826 pool_page_free_nointr(struct pool *pp, v |
|
Line 2910 pool_page_free_nointr(struct pool *pp, v |
|
|
|
uvm_km_free_poolpage_cache(kernel_map, (vaddr_t) v); |
uvm_km_free_poolpage_cache(kernel_map, (vaddr_t) v); |
} |
} |
|
|
|
#if defined(DDB) |
|
static bool |
|
pool_in_page(struct pool *pp, struct pool_item_header *ph, uintptr_t addr) |
|
{ |
|
|
|
return (uintptr_t)ph->ph_page <= addr && |
|
addr < (uintptr_t)ph->ph_page + pp->pr_alloc->pa_pagesz; |
|
} |
|
|
|
void |
|
pool_whatis(uintptr_t addr, void (*pr)(const char *, ...)) |
|
{ |
|
struct pool *pp; |
|
|
|
LIST_FOREACH(pp, &pool_head, pr_poollist) { |
|
struct pool_item_header *ph; |
|
uintptr_t item; |
|
|
|
if ((pp->pr_roflags & PR_PHINPAGE) != 0) { |
|
LIST_FOREACH(ph, &pp->pr_fullpages, ph_pagelist) { |
|
if (pool_in_page(pp, ph, addr)) { |
|
goto found; |
|
} |
|
} |
|
LIST_FOREACH(ph, &pp->pr_partpages, ph_pagelist) { |
|
if (pool_in_page(pp, ph, addr)) { |
|
goto found; |
|
} |
|
} |
|
continue; |
|
} else { |
|
ph = pr_find_pagehead_noalign(pp, (void *)addr); |
|
if (ph == NULL || !pool_in_page(pp, ph, addr)) { |
|
continue; |
|
} |
|
} |
|
found: |
|
item = (uintptr_t)ph->ph_page + ph->ph_off; |
|
item = item + rounddown(addr - item, pp->pr_size); |
|
(*pr)("%p is %p+%zu from POOL '%s'\n", |
|
(void *)addr, item, (size_t)(addr - item), |
|
pp->pr_wchan); |
|
} |
|
} |
|
#endif /* defined(DDB) */ |