add SLIB allocator for arch/lib (CONFIG_LIB) to wrap kmalloc and co. This will bring user's own allocator of libos: malloc(3) etc. Signed-off-by: Hajime Tazaki <tazaki@xxxxxxxxxxxxxx> --- include/linux/slab.h | 6 +- include/linux/slib_def.h | 21 +++++ init/Kconfig | 8 ++ mm/Makefile | 1 + mm/slab.h | 4 + mm/slib.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 include/linux/slib_def.h create mode 100644 mm/slib.c diff --git a/include/linux/slab.h b/include/linux/slab.h index 9a139b6..b167daa 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -192,7 +192,7 @@ size_t ksize(const void *); #endif #endif -#ifdef CONFIG_SLOB +#if defined(CONFIG_SLOB) || defined(CONFIG_SLIB) /* * SLOB passes all requests larger than one page to the page allocator. * No kmalloc array is necessary since objects of different sizes can @@ -350,6 +350,9 @@ kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order) } #endif +#ifdef CONFIG_SLIB +#include <linux/slib_def.h> +#else static __always_inline void *kmalloc_large(size_t size, gfp_t flags) { unsigned int order = get_order(size); @@ -428,6 +431,7 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags) } return __kmalloc(size, flags); } +#endif /* CONFIG_SLIB */ /* * Determine size used for the nth kmalloc cache. diff --git a/include/linux/slib_def.h b/include/linux/slib_def.h new file mode 100644 index 0000000..d9fe7d5 --- /dev/null +++ b/include/linux/slib_def.h @@ -0,0 +1,21 @@ +#ifndef _LINUX_SLLB_DEF_H +#define _LINUX_SLLB_DEF_H + + +struct kmem_cache { + unsigned int object_size; + const char *name; + size_t size; + size_t align; + unsigned long flags; + void (*ctor)(void *); +}; + +void *__kmalloc(size_t size, gfp_t flags); +void *kmem_cache_alloc(struct kmem_cache *, gfp_t); +static __always_inline void *kmalloc(size_t size, gfp_t flags) +{ + return __kmalloc(size, flags); +} + +#endif /* _LINUX_SLLB_DEF_H */ diff --git a/init/Kconfig b/init/Kconfig index 9afb971..8bdee98 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1695,6 +1695,14 @@ config SLOB allocator. SLOB is generally more space efficient but does not perform as well on large systems. +config SLIB + bool "SLIB (Library Allocator)" + depends on LIB + help + SLIB replaces the slab allocator with a registered allocator + function via lib_init() used by libos (CONFIG_LIB). It usually + used malloc(3) or any allocators. + endchoice config SLUB_CPU_PARTIAL diff --git a/mm/Makefile b/mm/Makefile index 4bf586e..8c66951 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_NUMA) += mempolicy.o obj-$(CONFIG_SPARSEMEM) += sparse.o obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o obj-$(CONFIG_SLOB) += slob.o +obj-$(CONFIG_SLIB) += slib.o obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o obj-$(CONFIG_KSM) += ksm.o obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o diff --git a/mm/slab.h b/mm/slab.h index 1cf40054..89c2319 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -37,6 +37,10 @@ struct kmem_cache { #include <linux/slub_def.h> #endif +#ifdef CONFIG_SLIB +#include <linux/slib_def.h> +#endif + #include <linux/memcontrol.h> /* diff --git a/mm/slib.c b/mm/slib.c new file mode 100644 index 0000000..37596862 --- /dev/null +++ b/mm/slib.c @@ -0,0 +1,205 @@ +/* + * Library Slab Allocator (SLIB) + * + * Copyright (c) 2015 INRIA, Hajime Tazaki + * + * Author: Mathieu Lacage <mathieu.lacage@xxxxxxxxx> + * Hajime Tazaki <tazaki@xxxxxxxxxxxxxx> + */ + +#include "sim.h" +#include "sim-assert.h" +#include <linux/page-flags.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/slib_def.h> + +/* glues */ +struct kmem_cache *files_cachep; + +void kfree(const void *p) +{ + unsigned long start; + + if (p == 0) + return; + start = (unsigned long)p; + start -= sizeof(size_t); + lib_free((void *)start); +} +size_t ksize(const void *p) +{ + size_t *psize = (size_t *)p; + + psize--; + return *psize; +} +void *__kmalloc(size_t size, gfp_t flags) +{ + void *p = lib_malloc(size + sizeof(size)); + unsigned long start; + + if (!p) + return NULL; + + if (p != 0 && (flags & __GFP_ZERO)) + lib_memset(p, 0, size + sizeof(size)); + lib_memcpy(p, &size, sizeof(size)); + start = (unsigned long)p; + return (void *)(start + sizeof(size)); +} + +void *__kmalloc_track_caller(size_t size, gfp_t flags, unsigned long caller) +{ + return kmalloc(size, flags); +} + +void *krealloc(const void *p, size_t new_size, gfp_t flags) +{ + void *ret; + + if (!new_size) { + kfree(p); + return ZERO_SIZE_PTR; + } + + ret = __kmalloc(new_size, flags); + if (ret && p != ret) + kfree(p); + + return ret; +} + +struct kmem_cache * +kmem_cache_create(const char *name, size_t size, size_t align, + unsigned long flags, void (*ctor)(void *)) +{ + struct kmem_cache *cache = kmalloc(sizeof(struct kmem_cache), flags); + + if (!cache) + return NULL; + cache->name = name; + cache->size = size; + cache->align = align; + cache->flags = flags; + cache->ctor = ctor; + return cache; +} +void kmem_cache_destroy(struct kmem_cache *cache) +{ + kfree(cache); +} +int kmem_cache_shrink(struct kmem_cache *cache) +{ + return 1; +} +const char *kmem_cache_name(struct kmem_cache *cache) +{ + return cache->name; +} +void *kmem_cache_alloc(struct kmem_cache *cache, gfp_t flags) +{ + void *p = kmalloc(cache->size, flags); + + if (p == 0) + return NULL; + if (cache->ctor) + (cache->ctor)(p); + return p; + +} +void kmem_cache_free(struct kmem_cache *cache, void *p) +{ + kfree(p); +} + +struct page * +__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, + struct zonelist *zonelist, nodemask_t *nodemask) +{ + void *p; + struct page *page; + unsigned long pointer; + + /* typically, called from networking code by alloc_page or */ + /* directly with an order = 0. */ + if (order) + return NULL; + p = lib_malloc(sizeof(struct page) + (1 << PAGE_SHIFT)); + page = (struct page *)p; + + atomic_set(&page->_count, 1); + page->flags = 0; + pointer = (unsigned long)page; + pointer += sizeof(struct page); + page->virtual = (void *)pointer; + return page; +} +void __free_pages(struct page *page, unsigned int order) +{ + /* typically, called from networking code by __free_page */ + lib_assert(order == 0); + lib_free(page); +} + +void put_page(struct page *page) +{ + if (atomic_dec_and_test(&page->_count)) + lib_free(page); +} +unsigned long get_zeroed_page(gfp_t gfp_mask) +{ + return __get_free_pages(gfp_mask | __GFP_ZERO, 0); +} + +void *alloc_pages_exact(size_t size, gfp_t gfp_mask) +{ + return alloc_pages(gfp_mask, get_order(size)); +} + +unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order) +{ + int size = (1 << order) * PAGE_SIZE; + void *p = kmalloc(size, gfp_mask); + + return (unsigned long)p; +} +void free_pages(unsigned long addr, unsigned int order) +{ + if (addr != 0) + kfree((void *)addr); +} + +void *vmalloc(unsigned long size) +{ + return lib_malloc(size); +} +void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot) +{ + return kmalloc(size, gfp_mask); +} +void vfree(const void *addr) +{ + lib_free((void *)addr); +} +void *vmalloc_node(unsigned long size, int node) +{ + return lib_malloc(size); +} +void vmalloc_sync_all(void) +{ +} +void *__alloc_percpu(size_t size, size_t align) +{ + return kzalloc(size, GFP_KERNEL); +} +void free_percpu(void __percpu *ptr) +{ + kfree(ptr); +} +void *__alloc_bootmem_nopanic(unsigned long size, + unsigned long align, + unsigned long goal) +{ + return kzalloc(size, GFP_KERNEL); +} -- 2.1.0 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxx. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>