diff options
author | Richard Braun <rbraun@sceen.net> | 2016-02-06 23:06:33 +0100 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2016-02-06 23:11:21 +0100 |
commit | 0b07275f60923840dffc80d7b4adb9a1ad7799f5 (patch) | |
tree | b240f0a65143cc2514073adae568e5d477c1239c /kern/slab.c | |
parent | 44d78061e90e777b51cae8e01eda5c0d3ce63103 (diff) | |
download | gnumach-0b07275f60923840dffc80d7b4adb9a1ad7799f5.tar.gz gnumach-0b07275f60923840dffc80d7b4adb9a1ad7799f5.tar.bz2 gnumach-0b07275f60923840dffc80d7b4adb9a1ad7799f5.zip |
Change computation of slab size
Allocating directly out of the physical memory allocator makes the slab
allocator vulnerable to failures due to fragmentation. This change makes
the slab allocator use the lowest possible size for its slabs to reduce
the chance of contiguous allocation failures.
* kern/slab.c (KMEM_MIN_BUFS_PER_SLAB, KMEM_SLAB_SIZE_THRESHOLD): Remove
macros.
(kmem_cache_compute_sizes): Update the algorithm used to determine slab
size and other cache properties.
Diffstat (limited to 'kern/slab.c')
-rw-r--r-- | kern/slab.c | 82 |
1 files changed, 26 insertions, 56 deletions
diff --git a/kern/slab.c b/kern/slab.c index f1a534a8..d18c10b4 100644 --- a/kern/slab.c +++ b/kern/slab.c @@ -112,19 +112,6 @@ #define KMEM_ALIGN_MIN 8 /* - * Minimum number of buffers per slab. - * - * This value is ignored when the slab size exceeds a threshold. - */ -#define KMEM_MIN_BUFS_PER_SLAB 8 - -/* - * Special slab size beyond which the minimum number of buffers per slab is - * ignored when computing the slab size of a cache. - */ -#define KMEM_SLAB_SIZE_THRESHOLD (8 * PAGE_SIZE) - -/* * Special buffer size under which slab data is unconditionnally allocated * from its associated slab. */ @@ -697,64 +684,47 @@ static void kmem_cache_error(struct kmem_cache *cache, void *buf, int error, */ static void kmem_cache_compute_sizes(struct kmem_cache *cache, int flags) { - size_t i, buffers, buf_size, slab_size, free_slab_size; - size_t waste, waste_min, optimal_size = optimal_size; - int embed, optimal_embed = optimal_embed; - unsigned int slab_order; + size_t size, waste; + unsigned int order; + int embed; - buf_size = cache->buf_size; - - if (buf_size < KMEM_BUF_SIZE_THRESHOLD) + if (cache->buf_size < KMEM_BUF_SIZE_THRESHOLD) flags |= KMEM_CACHE_NOOFFSLAB; - i = 0; - waste_min = (size_t)-1; - - do { - i++; - - slab_order = vm_page_order(i * buf_size); - slab_size = PAGE_SIZE << slab_order; - free_slab_size = slab_size; - - if (flags & KMEM_CACHE_NOOFFSLAB) - free_slab_size -= sizeof(struct kmem_slab); - - buffers = free_slab_size / buf_size; - waste = free_slab_size % buf_size; + /* + * In order to cope with physical memory fragmentation, the slab size is + * chosen as the lowest possible allocation order. + */ + order = vm_page_order(cache->buf_size); - if (buffers > i) - i = buffers; + for (;;) { + cache->slab_size = PAGE_SIZE << order; if (flags & KMEM_CACHE_NOOFFSLAB) embed = 1; - else if (sizeof(struct kmem_slab) <= waste) { - embed = 1; - waste -= sizeof(struct kmem_slab); - } else { - embed = 0; + else { + waste = cache->slab_size % cache->buf_size; + embed = (sizeof(struct kmem_slab) <= waste); } - if (waste <= waste_min) { - waste_min = waste; - optimal_size = slab_size; - optimal_embed = embed; - } - } while ((buffers < KMEM_MIN_BUFS_PER_SLAB) - && (slab_size < KMEM_SLAB_SIZE_THRESHOLD)); + size = cache->slab_size; + + if (embed) + size -= sizeof(struct kmem_slab); - assert(!(flags & KMEM_CACHE_NOOFFSLAB) || optimal_embed); + if (size >= cache->buf_size) + break; + + order++; + } - cache->slab_size = optimal_size; - slab_size = cache->slab_size - - (optimal_embed ? sizeof(struct kmem_slab) : 0); - cache->bufs_per_slab = slab_size / buf_size; - cache->color_max = slab_size % buf_size; + cache->bufs_per_slab = size / cache->buf_size; + cache->color_max = size % cache->buf_size; if (cache->color_max >= PAGE_SIZE) cache->color_max = PAGE_SIZE - 1; - if (optimal_embed) { + if (embed) { if (cache->slab_size == PAGE_SIZE) cache->flags |= KMEM_CF_DIRECT; } else { |