1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
|
/* $NetBSD: pool.h,v 1.96 2021/12/22 16:57:28 thorpej Exp $ */
/*-
* Copyright (c) 1997, 1998, 1999, 2000, 2007, 2020
* The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Paul Kranenburg; by Jason R. Thorpe of the Numerical Aerospace
* Simulation Facility, NASA Ames Research Center.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SYS_POOL_H_
#define _SYS_POOL_H_
#include <sys/stdbool.h>
#include <sys/stdint.h>
struct pool_sysctl {
char pr_wchan[16];
uint64_t pr_flags;
uint64_t pr_size;
uint64_t pr_pagesize;
uint64_t pr_itemsperpage;
uint64_t pr_nitems;
uint64_t pr_nout;
uint64_t pr_hardlimit;
uint64_t pr_npages;
uint64_t pr_minpages;
uint64_t pr_maxpages;
uint64_t pr_nget;
uint64_t pr_nfail;
uint64_t pr_nput;
uint64_t pr_npagealloc;
uint64_t pr_npagefree;
uint64_t pr_hiwat;
uint64_t pr_nidle;
uint64_t pr_cache_meta_size;
uint64_t pr_cache_nfull;
uint64_t pr_cache_npartial;
uint64_t pr_cache_nempty;
uint64_t pr_cache_ncontended;
uint64_t pr_cache_nmiss_global;
uint64_t pr_cache_nhit_global;
uint64_t pr_cache_nmiss_pcpu;
uint64_t pr_cache_nhit_pcpu;
};
#ifdef _KERNEL
#define __POOL_EXPOSE
#endif
#ifdef __POOL_EXPOSE
#include <sys/param.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/queue.h>
#include <sys/time.h>
#include <sys/tree.h>
#include <sys/callback.h>
#ifdef _KERNEL_OPT
#include "opt_pool.h"
#endif
#define POOL_PADDR_INVALID ((paddr_t) -1)
struct pool;
struct pool_allocator {
void *(*pa_alloc)(struct pool *, int);
void (*pa_free)(struct pool *, void *);
unsigned int pa_pagesz;
/* The following fields are for internal use only. */
kmutex_t pa_lock;
TAILQ_HEAD(, pool) pa_list; /* list of pools using this allocator */
uint32_t pa_refcnt; /* number of pools using this allocator */
int pa_pagemask;
int pa_pageshift;
};
LIST_HEAD(pool_pagelist,pool_item_header);
SPLAY_HEAD(phtree, pool_item_header);
#define POOL_QUARANTINE_DEPTH 128
typedef struct {
size_t rotor;
intptr_t list[POOL_QUARANTINE_DEPTH];
} pool_quar_t;
struct pool {
TAILQ_ENTRY(pool)
pr_poollist;
struct pool_pagelist
pr_emptypages; /* Empty pages */
struct pool_pagelist
pr_fullpages; /* Full pages */
struct pool_pagelist
pr_partpages; /* Partially-allocated pages */
struct pool_item_header *pr_curpage;
struct pool *pr_phpool; /* Pool item header pool */
struct pool_cache *pr_cache; /* Cache for this pool */
unsigned int pr_size; /* Size of item */
unsigned int pr_align; /* Requested alignment, must be 2^n */
unsigned int pr_itemoffset; /* offset of the item space */
unsigned int pr_minitems; /* minimum # of free items to keep */
unsigned int pr_maxitems; /* maximum # of free items to keep */
unsigned int pr_minpages; /* minimum # of pages to keep */
unsigned int pr_maxpages; /* maximum # of pages to keep */
unsigned int pr_npages; /* # of pages allocated */
unsigned int pr_itemsperpage;/* # items that fit in a page */
unsigned int pr_poolid; /* id of the pool */
unsigned int pr_nitems; /* number of free items in pool */
unsigned int pr_nout; /* # items currently allocated */
unsigned int pr_hardlimit; /* hard limit to number of allocated
items */
unsigned int pr_refcnt; /* ref count for pagedaemon, etc */
struct pool_allocator *pr_alloc;/* back-end allocator */
TAILQ_ENTRY(pool) pr_alloc_list;/* link on allocator's pool list */
/* Drain hook. */
void (*pr_drain_hook)(void *, int);
void *pr_drain_hook_arg;
const char *pr_wchan; /* tsleep(9) identifier */
unsigned int pr_flags; /* r/w flags */
unsigned int pr_roflags; /* r/o flags */
#define PR_WAITOK 0x01 /* Note: matches KM_SLEEP */
#define PR_NOWAIT 0x02 /* Note: matches KM_NOSLEEP */
#define PR_WANTED 0x04 /* waiting for free objects */
#define PR_PHINPAGE 0x40 /* page header in page */
#define PR_LIMITFAIL 0x100 /* even if waiting, fail if we hit limit */
#define PR_RECURSIVE 0x200 /* pool contains pools, for vmstat(8) */
#define PR_NOTOUCH 0x400 /* don't use free items to keep internal state*/
#define PR_NOALIGN 0x800 /* don't assume backend alignment */
#define PR_LARGECACHE 0x1000 /* use large cache groups */
#define PR_GROWING 0x2000 /* pool_grow in progress */
#define PR_GROWINGNOWAIT 0x4000 /* pool_grow in progress by PR_NOWAIT alloc */
#define PR_ZERO 0x8000 /* zero data before returning */
#define PR_USEBMAP 0x10000 /* use a bitmap to manage freed items */
#define PR_PSERIALIZE 0x20000 /* needs pserialize sync point before free */
/*
* `pr_lock' protects the pool's data structures when removing
* items from or returning items to the pool, or when reading
* or updating read/write fields in the pool descriptor.
*
* We assume back-end page allocators provide their own locking
* scheme. They will be called with the pool descriptor _unlocked_,
* since the page allocators may block.
*/
kmutex_t pr_lock;
kcondvar_t pr_cv;
int pr_ipl;
struct phtree pr_phtree;
int pr_maxcolor; /* Cache colouring */
int pr_curcolor;
int pr_phoffset; /* unused */
/*
* Warning message to be issued, and a per-time-delta rate cap,
* if the hard limit is reached.
*/
const char *pr_hardlimit_warning;
struct timeval pr_hardlimit_ratecap;
struct timeval pr_hardlimit_warning_last;
/*
* Instrumentation
*/
unsigned long pr_nget; /* # of successful requests */
unsigned long pr_nfail; /* # of unsuccessful requests */
unsigned long pr_nput; /* # of releases */
unsigned long pr_npagealloc; /* # of pages allocated */
unsigned long pr_npagefree; /* # of pages released */
unsigned int pr_hiwat; /* max # of pages in pool */
unsigned long pr_nidle; /* # of idle pages */
/*
* Diagnostic aides.
*/
void *pr_freecheck;
void *pr_qcache;
bool pr_redzone;
size_t pr_reqsize;
size_t pr_reqsize_with_redzone;
#ifdef POOL_QUARANTINE
pool_quar_t pr_quar;
#endif
};
/*
* Cache group sizes, assuming 4-byte paddr_t on !_LP64.
* All groups will be aligned to COHERENCY_UNIT.
*/
#ifdef _LP64
#define PCG_NOBJECTS_NORMAL 15 /* 256 byte group */
#define PCG_NOBJECTS_LARGE 63 /* 1024 byte group */
#else
#define PCG_NOBJECTS_NORMAL 14 /* 124 byte group */
#define PCG_NOBJECTS_LARGE 62 /* 508 byte group */
#endif
typedef struct pcgpair {
void *pcgo_va; /* object virtual address */
paddr_t pcgo_pa; /* object physical address */
} pcgpair_t;
/* The pool cache group. */
typedef struct pool_cache_group {
struct pool_cache_group *pcg_next; /* link to next group */
u_int pcg_avail; /* # available objects */
u_int pcg_size; /* max number objects */
pcgpair_t pcg_objects[1]; /* the objects */
} pcg_t;
/* Pool cache CPU. Sized to 64 bytes on _LP64. */
typedef struct pool_cache_cpu {
struct pool_cache_group *cc_current;
struct pool_cache_group *cc_previous;
pcg_t *volatile *cc_pcgcache;
uint64_t cc_misses;
uint64_t cc_hits;
uint64_t cc_pcmisses;
uint64_t cc_contended;
uint32_t cc_nfull;
uint32_t cc_npart;
} pool_cache_cpu_t;
struct pool_cache {
/* Pool layer. */
struct pool pc_pool;
/* Cache layer. */
TAILQ_ENTRY(pool_cache)
pc_cachelist; /* entry on global cache list */
struct pool *pc_pcgpool; /* Pool of cache groups */
pcg_t *volatile *pc_pcgcache; /* list of empty cache groups */
int pc_pcgsize; /* Use large cache groups? */
int pc_ncpu; /* number cpus set up */
int (*pc_ctor)(void *, void *, int);
void (*pc_dtor)(void *, void *);
void *pc_arg; /* for ctor/dtor */
unsigned int pc_refcnt; /* ref count for pagedaemon, etc */
unsigned int pc_roflags; /* r/o cache flags */
void *pc_cpus[MAXCPUS];
/* Diagnostic aides. */
void *pc_freecheck;
bool pc_redzone;
size_t pc_reqsize;
/* Hot items. */
pcg_t *volatile pc_fullgroups /* list of full cache groups */
__aligned(CACHE_LINE_SIZE);
pcg_t *volatile pc_partgroups; /* groups for reclamation */
/* Boot cpu. */
pool_cache_cpu_t pc_cpu0 __aligned(CACHE_LINE_SIZE);
};
#endif /* __POOL_EXPOSE */
typedef struct pool_cache *pool_cache_t;
#ifdef _KERNEL
/*
* pool_allocator_kmem is the default that all pools get unless
* otherwise specified. pool_allocator_nointr is provided for
* pools that know they will never be accessed in interrupt
* context.
*/
extern struct pool_allocator pool_allocator_kmem;
extern struct pool_allocator pool_allocator_nointr;
extern struct pool_allocator pool_allocator_meta;
void pool_subsystem_init(void);
void pool_init(struct pool *, size_t, u_int, u_int,
int, const char *, struct pool_allocator *, int);
void pool_destroy(struct pool *);
void pool_set_drain_hook(struct pool *,
void (*)(void *, int), void *);
void *pool_get(struct pool *, int);
void pool_put(struct pool *, void *);
int pool_reclaim(struct pool *);
void pool_prime(struct pool *, int);
void pool_setlowat(struct pool *, int);
void pool_sethiwat(struct pool *, int);
void pool_sethardlimit(struct pool *, int, const char *, int);
bool pool_drain(struct pool **);
int pool_totalpages(void);
int pool_totalpages_locked(void);
unsigned int pool_nget(struct pool *);
unsigned int pool_nput(struct pool *);
/*
* Debugging and diagnostic aides.
*/
void pool_printit(struct pool *, const char *,
void (*)(const char *, ...) __printflike(1, 2));
void pool_printall(const char *, void (*)(const char *, ...)
__printflike(1, 2));
int pool_chk(struct pool *, const char *);
/*
* Pool cache routines.
*/
pool_cache_t pool_cache_init(size_t, u_int, u_int, u_int, const char *,
struct pool_allocator *, int, int (*)(void *, void *, int),
void (*)(void *, void *), void *);
void pool_cache_bootstrap(pool_cache_t, size_t, u_int, u_int, u_int,
const char *, struct pool_allocator *, int,
int (*)(void *, void *, int), void (*)(void *, void *),
void *);
void pool_cache_destroy(pool_cache_t);
void pool_cache_bootstrap_destroy(pool_cache_t);
void *pool_cache_get_paddr(pool_cache_t, int, paddr_t *);
void pool_cache_put_paddr(pool_cache_t, void *, paddr_t);
void pool_cache_destruct_object(pool_cache_t, void *);
void pool_cache_invalidate(pool_cache_t);
bool pool_cache_reclaim(pool_cache_t);
void pool_cache_set_drain_hook(pool_cache_t,
void (*)(void *, int), void *);
void pool_cache_setlowat(pool_cache_t, int);
void pool_cache_sethiwat(pool_cache_t, int);
void pool_cache_sethardlimit(pool_cache_t, int, const char *, int);
void pool_cache_prime(pool_cache_t, int);
void pool_cache_cpu_init(struct cpu_info *);
unsigned int pool_cache_nget(pool_cache_t);
unsigned int pool_cache_nput(pool_cache_t);
#define pool_cache_get(pc, f) pool_cache_get_paddr((pc), (f), NULL)
#define pool_cache_put(pc, o) pool_cache_put_paddr((pc), (o), \
POOL_PADDR_INVALID)
void pool_whatis(uintptr_t, void (*)(const char *, ...)
__printflike(1, 2));
#endif /* _KERNEL */
#endif /* _SYS_POOL_H_ */
|