From: Kent Overstreet Date: Sun, 12 Nov 2017 21:48:07 +0000 (-0500) Subject: Simple stupid memory reclaim code X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=3347339bbd1e39fbb254d3d80f10b2e3b4d19e6e;p=bcachefs-tools-debian Simple stupid memory reclaim code --- diff --git a/Makefile b/Makefile index 9859b02..a5ea2d0 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ CFLAGS+=-std=gnu89 -O2 -g -MMD -Wall \ -DNO_BCACHEFS_FS \ -DNO_BCACHEFS_SYSFS \ $(EXTRA_CFLAGS) -LDFLAGS+=-O2 -g +LDFLAGS+=$(CFLAGS) CC_VERSION=$(shell $(CC) -v 2>&1|grep -E '(gcc|clang) version') diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h index baa36b1..6b0db3f 100644 --- a/include/linux/shrinker.h +++ b/include/linux/shrinker.h @@ -19,7 +19,9 @@ struct shrinker { struct list_head list; }; -static inline int register_shrinker(struct shrinker *shrinker) { return 0; } -static inline void unregister_shrinker(struct shrinker *shrinker) {} +int register_shrinker(struct shrinker *); +void unregister_shrinker(struct shrinker *); + +void run_shrinkers(void); #endif /* __TOOLS_LINUX_SHRINKER_H */ diff --git a/include/linux/slab.h b/include/linux/slab.h index d0d8790..9229e75 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -7,6 +7,7 @@ #include #include +#include #include #define ARCH_KMALLOC_MINALIGN 16 @@ -14,8 +15,11 @@ static inline void *kmalloc(size_t size, gfp_t flags) { - void *p = malloc(size); + void *p; + run_shrinkers(); + + p = malloc(size); if (p && (flags & __GFP_ZERO)) memset(p, 0, size); @@ -24,24 +28,31 @@ static inline void *kmalloc(size_t size, gfp_t flags) static inline void *krealloc(void *old, size_t size, gfp_t flags) { - void *new = kmalloc(size, flags); + void *new; + + run_shrinkers(); + + new = malloc(size); + if (!new) + return NULL; - if (new && (flags & __GFP_ZERO)) + if (flags & __GFP_ZERO) memset(new, 0, size); - if (new) { - memcpy(new, old, - min(malloc_usable_size(old), - malloc_usable_size(new))); - free(old); - } + memcpy(new, old, + min(malloc_usable_size(old), + malloc_usable_size(new))); + free(old); return new; } -#define kzalloc(size, flags) calloc(1, size) -#define kcalloc(n, size, flags) calloc(n, size) -#define kmalloc_array(n, size, flags) calloc(n, size) +#define kzalloc(size, flags) kmalloc(size, flags|__GFP_ZERO) +#define kmalloc_array(n, size, flags) \ + ((size) != 0 && (n) > SIZE_MAX / (size) \ + ? NULL : kmalloc(n * size, flags)) + +#define kcalloc(n, size, flags) kmalloc_array(n, size, flags|__GFP_ZERO) #define kfree(p) free(p) #define kvfree(p) free(p) @@ -50,8 +61,11 @@ static inline void *krealloc(void *old, size_t size, gfp_t flags) static inline struct page *alloc_pages(gfp_t flags, unsigned int order) { size_t size = PAGE_SIZE << order; - void *p = memalign(PAGE_SIZE, size); + void *p; + + run_shrinkers(); + p = aligned_alloc(PAGE_SIZE, size); if (p && (flags & __GFP_ZERO)) memset(p, 0, size); @@ -91,7 +105,7 @@ static inline void vunmap(const void *addr) {} static inline void *vmap(struct page **pages, unsigned int count, unsigned long flags, unsigned prot) { - return page_address(pages[0]); + return NULL; } #define is_vmalloc_addr(page) 0 diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index debdced..c91e3a8 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -4,6 +4,7 @@ #include #include +#include "linux/slab.h" #include "tools-util.h" #define PAGE_KERNEL 0 @@ -13,16 +14,21 @@ static inline void *__vmalloc(unsigned long size, gfp_t gfp_mask, unsigned prot) { - void *p = aligned_alloc(PAGE_SIZE, size); + void *p; - if (p && prot == PAGE_KERNEL_EXEC) { - if (mprotect(p, size, PROT_READ|PROT_WRITE|PROT_EXEC)) { - vfree(p); - p = NULL; - } + run_shrinkers(); + + p = aligned_alloc(PAGE_SIZE, size); + if (!p) + return NULL; + + if (prot == PAGE_KERNEL_EXEC && + mprotect(p, size, PROT_READ|PROT_WRITE|PROT_EXEC)) { + vfree(p); + return NULL; } - if (p && (gfp_mask & __GFP_ZERO)) + if (gfp_mask & __GFP_ZERO) memset(p, 0, size); return p; diff --git a/libbcachefs.h b/libbcachefs.h index bea80bb..99a4c13 100644 --- a/libbcachefs.h +++ b/libbcachefs.h @@ -64,7 +64,7 @@ struct dev_opts { static inline struct dev_opts dev_opts_default() { return (struct dev_opts) { - .data_allowed = ~0 << 2, + .data_allowed = ~0U << 2, }; } diff --git a/linux/shrinker.c b/linux/shrinker.c new file mode 100644 index 0000000..b8fc246 --- /dev/null +++ b/linux/shrinker.c @@ -0,0 +1,87 @@ + +#include + +#include +#include +#include + +#include "tools-util.h" + +static LIST_HEAD(shrinker_list); +static DEFINE_MUTEX(shrinker_lock); + +int register_shrinker(struct shrinker *shrinker) +{ + mutex_lock(&shrinker_lock); + list_add_tail(&shrinker->list, &shrinker_list); + mutex_unlock(&shrinker_lock); + return 0; +} + +void unregister_shrinker(struct shrinker *shrinker) +{ + mutex_lock(&shrinker_lock); + list_del(&shrinker->list); + mutex_unlock(&shrinker_lock); +} + +struct meminfo { + u64 total; + u64 available; + +}; + +static u64 parse_meminfo_line(const char *line) +{ + u64 v; + + if (sscanf(line, " %llu kB", &v) < 1) + die("sscanf error"); + return v << 10; +} + +static struct meminfo read_meminfo(void) +{ + struct meminfo ret = { 0 }; + size_t len, n = 0; + char *line = NULL; + const char *v; + FILE *f; + + f = fopen("/proc/meminfo", "r"); + if (!f) + die("error opening /proc/meminfo: %m"); + + while ((len = getline(&line, &n, f)) != -1) { + if ((v = strcmp_prefix(line, "MemTotal:"))) + ret.total = parse_meminfo_line(v); + + if ((v = strcmp_prefix(line, "MemAvailable:"))) + ret.available = parse_meminfo_line(v); + } + + fclose(f); + free(line); + + return ret; +} + +void run_shrinkers(void) +{ + struct shrinker *shrinker; + struct meminfo info = read_meminfo(); + s64 want_shrink = (info.total >> 2) - info.available; + + if (want_shrink <= 0) + return; + + mutex_lock(&shrinker_lock); + list_for_each_entry(shrinker, &shrinker_list, list) { + struct shrink_control sc = { + .nr_to_scan = want_shrink >> PAGE_SHIFT + }; + + shrinker->scan_objects(shrinker, &sc); + } + mutex_unlock(&shrinker_lock); +}