summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2017-11-12 16:48:07 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2017-11-12 16:48:07 -0500
commit3347339bbd1e39fbb254d3d80f10b2e3b4d19e6e (patch)
treee10659d3772db2d238bcf0f814348e850107ea8b
parente9afb70d261e420e540b0c79a718e76b03b1182b (diff)
Simple stupid memory reclaim code
-rw-r--r--Makefile2
-rw-r--r--include/linux/shrinker.h6
-rw-r--r--include/linux/slab.h42
-rw-r--r--include/linux/vmalloc.h20
-rw-r--r--libbcachefs.h2
-rw-r--r--linux/shrinker.c87
6 files changed, 134 insertions, 25 deletions
diff --git a/Makefile b/Makefile
index 9859b020..a5ea2d0a 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 baa36b1a..6b0db3fd 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 d0d8790d..9229e750 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -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
@@ -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 debdcedb..c91e3a80 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <sys/mman.h>
+#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 bea80bb9..99a4c132 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 00000000..b8fc2464
--- /dev/null
+++ b/linux/shrinker.c
@@ -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);
+}