]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
Simple stupid memory reclaim code
authorKent Overstreet <kent.overstreet@gmail.com>
Sun, 12 Nov 2017 21:48:07 +0000 (16:48 -0500)
committerKent Overstreet <kent.overstreet@gmail.com>
Sun, 12 Nov 2017 21:48:07 +0000 (16:48 -0500)
Makefile
include/linux/shrinker.h
include/linux/slab.h
include/linux/vmalloc.h
libbcachefs.h
linux/shrinker.c [new file with mode: 0644]

index 9859b020a156130b75edce732a590d6bb3d37cfd..a5ea2d0afaa38ccd2e60b3e7cd70e97c6d7ba7ea 100644 (file)
--- 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')
 
index baa36b1a9fc88de8239a7be118d6f519aa8c09d6..6b0db3fd5d2613d3ffa6ff8767043effbefb17f0 100644 (file)
@@ -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 */
index d0d8790db080d1c7e1e3c5be063ec5bcbdc91c64..9229e7503726f8ba854455da31b3930c0b5d434f 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/kernel.h>
 #include <linux/page.h>
+#include <linux/shrinker.h>
 #include <linux/types.h>
 
 #define ARCH_KMALLOC_MINALIGN          16
 
 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
index debdcedbea6d05fd520f3af82e37911bf1ec668c..c91e3a80ada8e4d7093b18a40107c7776f140e31 100644 (file)
@@ -4,6 +4,7 @@
 #include <stdlib.h>
 #include <sys/mman.h>
 
+#include "linux/slab.h"
 #include "tools-util.h"
 
 #define PAGE_KERNEL            0
 
 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;
index bea80bb9ba48f46c822e952e0f0c611a9d8e19ec..99a4c13282b78a7f851e980b094e595168f05f88 100644 (file)
@@ -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 (file)
index 0000000..b8fc246
--- /dev/null
@@ -0,0 +1,87 @@
+
+#include <stdio.h>
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/shrinker.h>
+
+#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);
+}