diff for duplicates of <20100713101854.2835.69539.sendpatchset@danny.redhat> diff --git a/a/1.txt b/N1/1.txt index 620c552..24338d8 100644 --- a/a/1.txt +++ b/N1/1.txt @@ -965,9 +965,3 @@ index 056545e..ffcd315 100644 struct kmem_cache *s; -- 1.7.1.1 - --- -To unsubscribe, send a message with 'unsubscribe linux-mm' in -the body to majordomo@kvack.org. For more info on Linux MM, -see: http://www.linux-mm.org/ . -Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> diff --git a/a/content_digest b/N1/content_digest index 1eb4938..ef480bf 100644 --- a/a/content_digest +++ b/N1/content_digest @@ -982,12 +982,6 @@ " {\n" " \tstruct kmem_cache *s;\n" "-- \n" - "1.7.1.1\n" - "\n" - "--\n" - "To unsubscribe, send a message with 'unsubscribe linux-mm' in\n" - "the body to majordomo@kvack.org. For more info on Linux MM,\n" - "see: http://www.linux-mm.org/ .\n" - "Don't email: <a href=mailto:\"dont@kvack.org\"> email@kvack.org </a>" + 1.7.1.1 -b97a5f82a8f2ff0d8c199276e9cb9884da2323658a0e4362b707a050da72cc29 +a9b7a46a2bc65de91796f074889929c2e92196d385ad5a8ff64b4df0c8a8b7f1
diff --git a/a/1.txt b/N2/1.txt index 620c552..8b13789 100644 --- a/a/1.txt +++ b/N2/1.txt @@ -1,973 +1 @@ ->From c598d3bbb8b5e900ad0f8397b1acbe922003ac5d Mon Sep 17 00:00:00 2001 -From: Xiaotian Feng <dfeng@redhat.com> -Date: Tue, 13 Jul 2010 11:01:48 +0800 -Subject: [PATCH 11/30] mm: memory reserve management -Generic reserve management code. - -It provides methods to reserve and charge. Upon this, generic alloc/free style -reserve pools could be build, which could fully replace mempool_t -functionality. - -It should also allow for a Banker's algorithm replacement of __GFP_NOFAIL. - -[dfeng@redhat.com: build fix for CONFIG_SLAB] -Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> -Signed-off-by: Suresh Jayaraman <sjayaraman@suse.de> -Signed-off-by: Xiaotian Feng <dfeng@redhat.com> ---- - include/linux/reserve.h | 198 +++++++++++++++ - include/linux/slab.h | 25 +- - mm/Makefile | 2 +- - mm/reserve.c | 637 +++++++++++++++++++++++++++++++++++++++++++++++ - mm/slub.c | 2 +- - 5 files changed, 851 insertions(+), 13 deletions(-) - create mode 100644 include/linux/reserve.h - create mode 100644 mm/reserve.c - -diff --git a/include/linux/reserve.h b/include/linux/reserve.h -new file mode 100644 -index 0000000..e1d3dbb ---- /dev/null -+++ b/include/linux/reserve.h -@@ -0,0 +1,198 @@ -+/* -+ * Memory reserve management. -+ * -+ * Copyright (C) 2007-2008 Red Hat, Inc., -+ * Peter Zijlstra <pzijlstr@redhat.com> -+ * -+ * This file contains the public data structure and API definitions. -+ */ -+ -+#ifndef _LINUX_RESERVE_H -+#define _LINUX_RESERVE_H -+ -+#include <linux/list.h> -+#include <linux/spinlock.h> -+#include <linux/wait.h> -+#include <linux/slab.h> -+ -+struct mem_reserve { -+ struct mem_reserve *parent; -+ struct list_head children; -+ struct list_head siblings; -+ -+ const char *name; -+ -+ long pages; -+ long limit; -+ long usage; -+ spinlock_t lock; /* protects limit and usage */ -+ -+ wait_queue_head_t waitqueue; -+}; -+ -+extern struct mem_reserve mem_reserve_root; -+ -+void mem_reserve_init(struct mem_reserve *res, const char *name, -+ struct mem_reserve *parent); -+int mem_reserve_connect(struct mem_reserve *new_child, -+ struct mem_reserve *node); -+void mem_reserve_disconnect(struct mem_reserve *node); -+ -+int mem_reserve_pages_set(struct mem_reserve *res, long pages); -+int mem_reserve_pages_add(struct mem_reserve *res, long pages); -+int mem_reserve_pages_charge(struct mem_reserve *res, long pages); -+ -+int mem_reserve_kmalloc_set(struct mem_reserve *res, long bytes); -+int mem_reserve_kmalloc_charge(struct mem_reserve *res, long bytes); -+ -+struct kmem_cache; -+ -+int mem_reserve_kmem_cache_set(struct mem_reserve *res, -+ struct kmem_cache *s, -+ int objects); -+int mem_reserve_kmem_cache_charge(struct mem_reserve *res, -+ struct kmem_cache *s, long objs); -+ -+void *___kmalloc_reserve(size_t size, gfp_t flags, int node, unsigned long ip, -+ struct mem_reserve *res, int *emerg); -+ -+static inline -+void *__kmalloc_reserve(size_t size, gfp_t flags, int node, unsigned long ip, -+ struct mem_reserve *res, int *emerg) -+{ -+ void *obj; -+ -+ obj = __kmalloc_node_track_caller(size, -+ flags | __GFP_NOMEMALLOC | __GFP_NOWARN, node, ip); -+ if (!obj) -+ obj = ___kmalloc_reserve(size, flags, node, ip, res, emerg); -+ -+ return obj; -+} -+ -+/** -+ * kmalloc_reserve() - kmalloc() and charge against @res for @emerg allocations -+ * @size - size of the requested memory region -+ * @gfp - allocation flags to use for this allocation -+ * @node - preferred memory node for this allocation -+ * @res - reserve to charge emergency allocations against -+ * @emerg - bit 0 is set when the allocation was an emergency allocation -+ * -+ * Returns NULL on failure -+ */ -+#define kmalloc_reserve(size, gfp, node, res, emerg) \ -+ __kmalloc_reserve(size, gfp, node, \ -+ _RET_IP_, res, emerg) -+ -+void __kfree_reserve(void *obj, struct mem_reserve *res, int emerg); -+ -+/** -+ * kfree_reserve() - kfree() and uncharge against @res for @emerg allocations -+ * @obj - memory to free -+ * @res - reserve to uncharge emergency allocations from -+ * @emerg - was this an emergency allocation -+ */ -+static inline -+void kfree_reserve(void *obj, struct mem_reserve *res, int emerg) -+{ -+ if (unlikely(obj && res && emerg)) -+ __kfree_reserve(obj, res, emerg); -+ else -+ kfree(obj); -+} -+ -+void *__kmem_cache_alloc_reserve(struct kmem_cache *s, gfp_t flags, int node, -+ struct mem_reserve *res, int *emerg); -+ -+/** -+ * kmem_cache_alloc_reserve() - kmem_cache_alloc() and charge against @res -+ * @s - kmem_cache to allocate from -+ * @gfp - allocation flags to use for this allocation -+ * @node - preferred memory node for this allocation -+ * @res - reserve to charge emergency allocations against -+ * @emerg - bit 0 is set when the allocation was an emergency allocation -+ * -+ * Returns NULL on failure -+ */ -+static inline -+void *kmem_cache_alloc_reserve(struct kmem_cache *s, gfp_t flags, int node, -+ struct mem_reserve *res, int *emerg) -+{ -+ void *obj; -+ -+ obj = kmem_cache_alloc_node(s, -+ flags | __GFP_NOMEMALLOC | __GFP_NOWARN, node); -+ if (!obj) -+ obj = __kmem_cache_alloc_reserve(s, flags, node, res, emerg); -+ -+ return obj; -+} -+ -+void __kmem_cache_free_reserve(struct kmem_cache *s, void *obj, -+ struct mem_reserve *res, int emerg); -+ -+/** -+ * kmem_cache_free_reserve() - kmem_cache_free() and uncharge against @res -+ * @s - kmem_cache to free to -+ * @obj - memory to free -+ * @res - reserve to uncharge emergency allocations from -+ * @emerg - was this an emergency allocation -+ */ -+static inline -+void kmem_cache_free_reserve(struct kmem_cache *s, void *obj, -+ struct mem_reserve *res, int emerg) -+{ -+ if (unlikely(obj && res && emerg)) -+ __kmem_cache_free_reserve(s, obj, res, emerg); -+ else -+ kmem_cache_free(s, obj); -+} -+ -+struct page *__alloc_pages_reserve(int node, gfp_t flags, int order, -+ struct mem_reserve *res, int *emerg); -+ -+/** -+ * alloc_pages_reserve() - alloc_pages() and charge against @res -+ * @node - preferred memory node for this allocation -+ * @gfp - allocation flags to use for this allocation -+ * @order - page order -+ * @res - reserve to charge emergency allocations against -+ * @emerg - bit 0 is set when the allocation was an emergency allocation -+ * -+ * Returns NULL on failure -+ */ -+static inline -+struct page *alloc_pages_reserve(int node, gfp_t flags, int order, -+ struct mem_reserve *res, int *emerg) -+{ -+ struct page *page; -+ -+ page = alloc_pages_node(node, -+ flags | __GFP_NOMEMALLOC | __GFP_NOWARN, order); -+ if (!page) -+ page = __alloc_pages_reserve(node, flags, order, res, emerg); -+ -+ return page; -+} -+ -+void __free_pages_reserve(struct page *page, int order, -+ struct mem_reserve *res, int emerg); -+ -+/** -+ * free_pages_reserve() - __free_pages() and uncharge against @res -+ * @page - page to free -+ * @order - page order -+ * @res - reserve to uncharge emergency allocations from -+ * @emerg - was this an emergency allocation -+ */ -+static inline -+void free_pages_reserve(struct page *page, int order, -+ struct mem_reserve *res, int emerg) -+{ -+ if (unlikely(page && res && emerg)) -+ __free_pages_reserve(page, order, res, emerg); -+ else -+ __free_pages(page, order); -+} -+ -+#endif /* _LINUX_RESERVE_H */ -diff --git a/include/linux/slab.h b/include/linux/slab.h -index b57b9ca..68195a7 100644 ---- a/include/linux/slab.h -+++ b/include/linux/slab.h -@@ -272,15 +272,17 @@ static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep, - * allocator where we care about the real place the memory allocation - * request comes from. - */ --#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) -+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || \ -+ (defined(CONFIG_SLAB) && defined(CONFIG_TRACING)) - extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long); --#define kmalloc_track_caller(size, flags) \ -- __kmalloc_track_caller(size, flags, _RET_IP_) - #else --#define kmalloc_track_caller(size, flags) \ -+#define __kmalloc_track_caller(size, flags, ip) \ - __kmalloc(size, flags) - #endif /* DEBUG_SLAB */ - -+#define kmalloc_track_caller(size, flags) \ -+ __kmalloc_track_caller(size, flags, _RET_IP_) -+ - #ifdef CONFIG_NUMA - /* - * kmalloc_node_track_caller is a special version of kmalloc_node that -@@ -290,23 +292,24 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long); - * standard allocator where we care about the real place the memory - * allocation request comes from. - */ --#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) -+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || \ -+ (defined(CONFIG_SLAB) && defined(CONFIG_TRACING)) - extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, unsigned long); --#define kmalloc_node_track_caller(size, flags, node) \ -- __kmalloc_node_track_caller(size, flags, node, \ -- _RET_IP_) - #else --#define kmalloc_node_track_caller(size, flags, node) \ -+#define __kmalloc_node_track_caller(size, flags, node, ip) \ - __kmalloc_node(size, flags, node) - #endif - - #else /* CONFIG_NUMA */ - --#define kmalloc_node_track_caller(size, flags, node) \ -- kmalloc_track_caller(size, flags) -+#define __kmalloc_node_track_caller(size, flags, node, ip) \ -+ __kmalloc_track_caller(size, flags, ip) - - #endif /* CONFIG_NUMA */ - -+#define kmalloc_node_track_caller(size, flags, node) \ -+ __kmalloc_node_track_caller(size, flags, node, \ -+ _RET_IP_) - /* - * Shortcuts - */ -diff --git a/mm/Makefile b/mm/Makefile -index 8982504..d1717bb 100644 ---- a/mm/Makefile -+++ b/mm/Makefile -@@ -11,7 +11,7 @@ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ - maccess.o page_alloc.o page-writeback.o \ - readahead.o swap.o truncate.o vmscan.o shmem.o \ - prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \ -- page_isolation.o mm_init.o mmu_context.o \ -+ page_isolation.o mm_init.o mmu_context.o reserve.o \ - $(mmu-y) - obj-y += init-mm.o - -diff --git a/mm/reserve.c b/mm/reserve.c -new file mode 100644 -index 0000000..2a00d72 ---- /dev/null -+++ b/mm/reserve.c -@@ -0,0 +1,637 @@ -+/* -+ * Memory reserve management. -+ * -+ * Copyright (C) 2007-2008, Red Hat, Inc., -+ * Peter Zijlstra <pzijlstr@redhat.com> -+ * -+ * Description: -+ * -+ * Manage a set of memory reserves. -+ * -+ * A memory reserve is a reserve for a specified number of object of specified -+ * size. Since memory is managed in pages, this reserve demand is then -+ * translated into a page unit. -+ * -+ * So each reserve has a specified object limit, an object usage count and a -+ * number of pages required to back these objects. -+ * -+ * Usage is charged against a reserve, if the charge fails, the resource must -+ * not be allocated/used. -+ * -+ * The reserves are managed in a tree, and the resource demands (pages and -+ * limit) are propagated up the tree. Obviously the object limit will be -+ * meaningless as soon as the unit starts mixing, but the required page reserve -+ * (being of one unit) is still valid at the root. -+ * -+ * It is the page demand of the root node that is used to set the global -+ * reserve (adjust_memalloc_reserve() which sets zone->pages_emerg). -+ * -+ * As long as a subtree has the same usage unit, an aggregate node can be used -+ * to charge against, instead of the leaf nodes. However, do be consistent with -+ * who is charged, resource usage is not propagated up the tree (for -+ * performance reasons). -+ */ -+ -+#include <linux/reserve.h> -+#include <linux/mutex.h> -+#include <linux/mmzone.h> -+#include <linux/log2.h> -+#include <linux/proc_fs.h> -+#include <linux/seq_file.h> -+#include <linux/module.h> -+#include <linux/slab.h> -+#include <linux/sched.h> -+#include "internal.h" -+ -+static DEFINE_MUTEX(mem_reserve_mutex); -+ -+/** -+ * @mem_reserve_root - the global reserve root -+ * -+ * The global reserve is empty, and has no limit unit, it merely -+ * acts as an aggregation point for reserves and an interface to -+ * adjust_memalloc_reserve(). -+ */ -+struct mem_reserve mem_reserve_root = { -+ .children = LIST_HEAD_INIT(mem_reserve_root.children), -+ .siblings = LIST_HEAD_INIT(mem_reserve_root.siblings), -+ .name = "total reserve", -+ .lock = __SPIN_LOCK_UNLOCKED(mem_reserve_root.lock), -+ .waitqueue = __WAIT_QUEUE_HEAD_INITIALIZER(mem_reserve_root.waitqueue), -+}; -+EXPORT_SYMBOL_GPL(mem_reserve_root); -+ -+/** -+ * mem_reserve_init() - initialize a memory reserve object -+ * @res - the new reserve object -+ * @name - a name for this reserve -+ * @parent - when non NULL, the parent to connect to. -+ */ -+void mem_reserve_init(struct mem_reserve *res, const char *name, -+ struct mem_reserve *parent) -+{ -+ memset(res, 0, sizeof(*res)); -+ INIT_LIST_HEAD(&res->children); -+ INIT_LIST_HEAD(&res->siblings); -+ res->name = name; -+ spin_lock_init(&res->lock); -+ init_waitqueue_head(&res->waitqueue); -+ -+ if (parent) -+ mem_reserve_connect(res, parent); -+} -+EXPORT_SYMBOL_GPL(mem_reserve_init); -+ -+/* -+ * propagate the pages and limit changes up the (sub)tree. -+ */ -+static void __calc_reserve(struct mem_reserve *res, long pages, long limit) -+{ -+ unsigned long flags; -+ -+ for ( ; res; res = res->parent) { -+ res->pages += pages; -+ -+ if (limit) { -+ spin_lock_irqsave(&res->lock, flags); -+ res->limit += limit; -+ spin_unlock_irqrestore(&res->lock, flags); -+ } -+ } -+} -+ -+/** -+ * __mem_reserve_add() - primitive to change the size of a reserve -+ * @res - reserve to change -+ * @pages - page delta -+ * @limit - usage limit delta -+ * -+ * Returns -ENOMEM when a size increase is not possible atm. -+ */ -+static int __mem_reserve_add(struct mem_reserve *res, long pages, long limit) -+{ -+ int ret = 0; -+ long reserve; -+ -+ /* -+ * This looks more complex than need be, that is because we handle -+ * the case where @res isn't actually connected to mem_reserve_root. -+ * -+ * So, by propagating the new pages up the (sub)tree and computing -+ * the difference in mem_reserve_root.pages we find if this action -+ * affects the actual reserve. -+ * -+ * The (partial) propagation also makes that mem_reserve_connect() -+ * needs only look at the direct child, since each disconnected -+ * sub-tree is fully up-to-date. -+ */ -+ reserve = mem_reserve_root.pages; -+ __calc_reserve(res, pages, 0); -+ reserve = mem_reserve_root.pages - reserve; -+ -+ if (reserve) { -+ ret = adjust_memalloc_reserve(reserve); -+ if (ret) -+ __calc_reserve(res, -pages, 0); -+ } -+ -+ /* -+ * Delay updating the limits until we've acquired the resources to -+ * back it. -+ */ -+ if (!ret) -+ __calc_reserve(res, 0, limit); -+ -+ return ret; -+} -+ -+/** -+ * __mem_reserve_charge() - primitive to charge object usage of a reserve -+ * @res - reserve to charge -+ * @charge - size of the charge -+ * -+ * Returns non-zero on success, zero on failure. -+ */ -+static -+int __mem_reserve_charge(struct mem_reserve *res, long charge) -+{ -+ unsigned long flags; -+ int ret = 0; -+ -+ spin_lock_irqsave(&res->lock, flags); -+ if (charge < 0 || res->usage + charge < res->limit) { -+ res->usage += charge; -+ if (unlikely(res->usage < 0)) -+ res->usage = 0; -+ ret = 1; -+ } -+ if (charge < 0) -+ wake_up_all(&res->waitqueue); -+ spin_unlock_irqrestore(&res->lock, flags); -+ -+ return ret; -+} -+ -+/** -+ * mem_reserve_connect() - connect a reserve to another in a child-parent relation -+ * @new_child - the reserve node to connect (child) -+ * @node - the reserve node to connect to (parent) -+ * -+ * Connecting a node results in an increase of the reserve by the amount of -+ * pages in @new_child->pages if @node has a connection to mem_reserve_root. -+ * -+ * Returns -ENOMEM when the new connection would increase the reserve (parent -+ * is connected to mem_reserve_root) and there is no memory to do so. -+ * -+ * On error, the child is _NOT_ connected. -+ */ -+int mem_reserve_connect(struct mem_reserve *new_child, struct mem_reserve *node) -+{ -+ int ret; -+ -+ WARN_ON(!new_child->name); -+ -+ mutex_lock(&mem_reserve_mutex); -+ if (new_child->parent) { -+ ret = -EEXIST; -+ goto unlock; -+ } -+ new_child->parent = node; -+ list_add(&new_child->siblings, &node->children); -+ ret = __mem_reserve_add(node, new_child->pages, new_child->limit); -+ if (ret) { -+ new_child->parent = NULL; -+ list_del_init(&new_child->siblings); -+ } -+unlock: -+ mutex_unlock(&mem_reserve_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(mem_reserve_connect); -+ -+/** -+ * mem_reserve_disconnect() - sever a nodes connection to the reserve tree -+ * @node - the node to disconnect -+ * -+ * Disconnecting a node results in a reduction of the reserve by @node->pages -+ * if node had a connection to mem_reserve_root. -+ */ -+void mem_reserve_disconnect(struct mem_reserve *node) -+{ -+ int ret; -+ -+ BUG_ON(!node->parent); -+ -+ mutex_lock(&mem_reserve_mutex); -+ if (!node->parent) { -+ ret = -ENOENT; -+ goto unlock; -+ } -+ ret = __mem_reserve_add(node->parent, -node->pages, -node->limit); -+ if (!ret) { -+ node->parent = NULL; -+ list_del_init(&node->siblings); -+ } -+unlock: -+ mutex_unlock(&mem_reserve_mutex); -+ -+ /* -+ * We cannot fail to shrink the reserves, can we? -+ */ -+ WARN_ON(ret); -+} -+EXPORT_SYMBOL_GPL(mem_reserve_disconnect); -+ -+#ifdef CONFIG_PROC_FS -+ -+/* -+ * Simple output of the reserve tree in: /proc/reserve_info -+ * Example: -+ * -+ * localhost ~ # cat /proc/reserve_info -+ * 1:0 "total reserve" 6232K 0/278581 -+ * 2:1 "total network reserve" 6232K 0/278581 -+ * 3:2 "network TX reserve" 212K 0/53 -+ * 4:3 "protocol TX pages" 212K 0/53 -+ * 5:2 "network RX reserve" 6020K 0/278528 -+ * 6:5 "IPv4 route cache" 5508K 0/16384 -+ * 7:5 "SKB data reserve" 512K 0/262144 -+ * 8:7 "IPv4 fragment cache" 512K 0/262144 -+ */ -+ -+static void mem_reserve_show_item(struct seq_file *m, struct mem_reserve *res, -+ unsigned int parent, unsigned int *id) -+{ -+ struct mem_reserve *child; -+ unsigned int my_id = ++*id; -+ -+ seq_printf(m, "%d:%d \"%s\" %ldK %ld/%ld\n", -+ my_id, parent, res->name, -+ res->pages << (PAGE_SHIFT - 10), -+ res->usage, res->limit); -+ -+ list_for_each_entry(child, &res->children, siblings) -+ mem_reserve_show_item(m, child, my_id, id); -+} -+ -+static int mem_reserve_show(struct seq_file *m, void *v) -+{ -+ unsigned int ident = 0; -+ -+ mutex_lock(&mem_reserve_mutex); -+ mem_reserve_show_item(m, &mem_reserve_root, ident, &ident); -+ mutex_unlock(&mem_reserve_mutex); -+ -+ return 0; -+} -+ -+static int mem_reserve_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, mem_reserve_show, NULL); -+} -+ -+static const struct file_operations mem_reserve_opterations = { -+ .open = mem_reserve_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static __init int mem_reserve_proc_init(void) -+{ -+ proc_create("reserve_info", S_IRUSR, NULL, &mem_reserve_opterations); -+ return 0; -+} -+ -+module_init(mem_reserve_proc_init); -+ -+#endif -+ -+/* -+ * alloc_page helpers -+ */ -+ -+/** -+ * mem_reserve_pages_set() - set reserves size in pages -+ * @res - reserve to set -+ * @pages - size in pages to set it to -+ * -+ * Returns -ENOMEM when it fails to set the reserve. On failure the old size -+ * is preserved. -+ */ -+int mem_reserve_pages_set(struct mem_reserve *res, long pages) -+{ -+ int ret; -+ -+ mutex_lock(&mem_reserve_mutex); -+ pages -= res->pages; -+ ret = __mem_reserve_add(res, pages, pages * PAGE_SIZE); -+ mutex_unlock(&mem_reserve_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(mem_reserve_pages_set); -+ -+/** -+ * mem_reserve_pages_add() - change the size in a relative way -+ * @res - reserve to change -+ * @pages - number of pages to add (or subtract when negative) -+ * -+ * Similar to mem_reserve_pages_set, except that the argument is relative -+ * instead of absolute. -+ * -+ * Returns -ENOMEM when it fails to increase. -+ */ -+int mem_reserve_pages_add(struct mem_reserve *res, long pages) -+{ -+ int ret; -+ -+ mutex_lock(&mem_reserve_mutex); -+ ret = __mem_reserve_add(res, pages, pages * PAGE_SIZE); -+ mutex_unlock(&mem_reserve_mutex); -+ -+ return ret; -+} -+ -+/** -+ * mem_reserve_pages_charge() - charge page usage to a reserve -+ * @res - reserve to charge -+ * @pages - size to charge -+ * -+ * Returns non-zero on success. -+ */ -+int mem_reserve_pages_charge(struct mem_reserve *res, long pages) -+{ -+ return __mem_reserve_charge(res, pages * PAGE_SIZE); -+} -+EXPORT_SYMBOL_GPL(mem_reserve_pages_charge); -+ -+/* -+ * kmalloc helpers -+ */ -+ -+/** -+ * mem_reserve_kmalloc_set() - set this reserve to bytes worth of kmalloc -+ * @res - reserve to change -+ * @bytes - size in bytes to reserve -+ * -+ * Returns -ENOMEM on failure. -+ */ -+int mem_reserve_kmalloc_set(struct mem_reserve *res, long bytes) -+{ -+ int ret; -+ long pages; -+ -+ mutex_lock(&mem_reserve_mutex); -+ pages = kmalloc_estimate_bytes(GFP_ATOMIC, bytes); -+ pages -= res->pages; -+ bytes -= res->limit; -+ ret = __mem_reserve_add(res, pages, bytes); -+ mutex_unlock(&mem_reserve_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(mem_reserve_kmalloc_set); -+ -+/** -+ * mem_reserve_kmalloc_charge() - charge bytes to a reserve -+ * @res - reserve to charge -+ * @bytes - bytes to charge -+ * -+ * Returns non-zero on success. -+ */ -+int mem_reserve_kmalloc_charge(struct mem_reserve *res, long bytes) -+{ -+ if (bytes < 0) -+ bytes = -roundup_pow_of_two(-bytes); -+ else -+ bytes = roundup_pow_of_two(bytes); -+ -+ return __mem_reserve_charge(res, bytes); -+} -+EXPORT_SYMBOL_GPL(mem_reserve_kmalloc_charge); -+ -+/* -+ * kmem_cache helpers -+ */ -+ -+/** -+ * mem_reserve_kmem_cache_set() - set reserve to @objects worth of kmem_cache_alloc of @s -+ * @res - reserve to set -+ * @s - kmem_cache to reserve from -+ * @objects - number of objects to reserve -+ * -+ * Returns -ENOMEM on failure. -+ */ -+int mem_reserve_kmem_cache_set(struct mem_reserve *res, struct kmem_cache *s, -+ int objects) -+{ -+ int ret; -+ long pages, bytes; -+ -+ mutex_lock(&mem_reserve_mutex); -+ pages = kmem_alloc_estimate(s, GFP_ATOMIC, objects); -+ pages -= res->pages; -+ bytes = objects * kmem_cache_size(s) - res->limit; -+ ret = __mem_reserve_add(res, pages, bytes); -+ mutex_unlock(&mem_reserve_mutex); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(mem_reserve_kmem_cache_set); -+ -+/** -+ * mem_reserve_kmem_cache_charge() - charge (or uncharge) usage of objs -+ * @res - reserve to charge -+ * @objs - objects to charge for -+ * -+ * Returns non-zero on success. -+ */ -+int mem_reserve_kmem_cache_charge(struct mem_reserve *res, struct kmem_cache *s, -+ long objs) -+{ -+ return __mem_reserve_charge(res, objs * kmem_cache_size(s)); -+} -+EXPORT_SYMBOL_GPL(mem_reserve_kmem_cache_charge); -+ -+/* -+ * Alloc wrappers. -+ * -+ * Actual usage is commented in linux/reserve.h where the interface functions -+ * live. Furthermore, the code is 3 instances of the same paradigm, hence only -+ * the first contains extensive comments. -+ */ -+ -+/* -+ * kmalloc/kfree -+ */ -+ -+void *___kmalloc_reserve(size_t size, gfp_t flags, int node, unsigned long ip, -+ struct mem_reserve *res, int *emerg) -+{ -+ void *obj; -+ gfp_t gfp; -+ -+ /* -+ * Try a regular allocation, when that fails and we're not entitled -+ * to the reserves, fail. -+ */ -+ gfp = flags | __GFP_NOMEMALLOC | __GFP_NOWARN; -+ obj = __kmalloc_node_track_caller(size, gfp, node, ip); -+ -+ if (obj || !(gfp_to_alloc_flags(flags) & ALLOC_NO_WATERMARKS)) -+ goto out; -+ -+ /* -+ * If we were given a reserve to charge against, try that. -+ */ -+ if (res && !mem_reserve_kmalloc_charge(res, size)) { -+ /* -+ * If we failed to charge and we're not allowed to wait for -+ * it to succeed, bail. -+ */ -+ if (!(flags & __GFP_WAIT)) -+ goto out; -+ -+ /* -+ * Wait for a successfull charge against the reserve. All -+ * uncharge operations against this reserve will wake us up. -+ */ -+ wait_event(res->waitqueue, -+ mem_reserve_kmalloc_charge(res, size)); -+ -+ /* -+ * After waiting for it, again try a regular allocation. -+ * Pressure could have lifted during our sleep. If this -+ * succeeds, uncharge the reserve. -+ */ -+ obj = __kmalloc_node_track_caller(size, gfp, node, ip); -+ if (obj) { -+ mem_reserve_kmalloc_charge(res, -size); -+ goto out; -+ } -+ } -+ -+ /* -+ * Regular allocation failed, and we've successfully charged our -+ * requested usage against the reserve. Do the emergency allocation. -+ */ -+ obj = __kmalloc_node_track_caller(size, flags, node, ip); -+ WARN_ON(!obj); -+ if (emerg) -+ *emerg = 1; -+ -+out: -+ return obj; -+} -+ -+void __kfree_reserve(void *obj, struct mem_reserve *res, int emerg) -+{ -+ /* -+ * ksize gives the full allocated size vs the requested size we used to -+ * charge; however since we round up to the nearest power of two, this -+ * should all work nicely. -+ */ -+ size_t size = ksize(obj); -+ -+ kfree(obj); -+ /* -+ * Free before uncharge, this ensures memory is actually present when -+ * a subsequent charge succeeds. -+ */ -+ mem_reserve_kmalloc_charge(res, -size); -+} -+ -+/* -+ * kmem_cache_alloc/kmem_cache_free -+ */ -+ -+void *__kmem_cache_alloc_reserve(struct kmem_cache *s, gfp_t flags, int node, -+ struct mem_reserve *res, int *emerg) -+{ -+ void *obj; -+ gfp_t gfp; -+ -+ gfp = flags | __GFP_NOMEMALLOC | __GFP_NOWARN; -+ obj = kmem_cache_alloc_node(s, gfp, node); -+ -+ if (obj || !(gfp_to_alloc_flags(flags) & ALLOC_NO_WATERMARKS)) -+ goto out; -+ -+ if (res && !mem_reserve_kmem_cache_charge(res, s, 1)) { -+ if (!(flags & __GFP_WAIT)) -+ goto out; -+ -+ wait_event(res->waitqueue, -+ mem_reserve_kmem_cache_charge(res, s, 1)); -+ -+ obj = kmem_cache_alloc_node(s, gfp, node); -+ if (obj) { -+ mem_reserve_kmem_cache_charge(res, s, -1); -+ goto out; -+ } -+ } -+ -+ obj = kmem_cache_alloc_node(s, flags, node); -+ WARN_ON(!obj); -+ if (emerg) -+ *emerg = 1; -+ -+out: -+ return obj; -+} -+ -+void __kmem_cache_free_reserve(struct kmem_cache *s, void *obj, -+ struct mem_reserve *res, int emerg) -+{ -+ kmem_cache_free(s, obj); -+ mem_reserve_kmem_cache_charge(res, s, -1); -+} -+ -+/* -+ * alloc_pages/free_pages -+ */ -+ -+struct page *__alloc_pages_reserve(int node, gfp_t flags, int order, -+ struct mem_reserve *res, int *emerg) -+{ -+ struct page *page; -+ gfp_t gfp; -+ long pages = 1 << order; -+ -+ gfp = flags | __GFP_NOMEMALLOC | __GFP_NOWARN; -+ page = alloc_pages_node(node, gfp, order); -+ -+ if (page || !(gfp_to_alloc_flags(flags) & ALLOC_NO_WATERMARKS)) -+ goto out; -+ -+ if (res && !mem_reserve_pages_charge(res, pages)) { -+ if (!(flags & __GFP_WAIT)) -+ goto out; -+ -+ wait_event(res->waitqueue, -+ mem_reserve_pages_charge(res, pages)); -+ -+ page = alloc_pages_node(node, gfp, order); -+ if (page) { -+ mem_reserve_pages_charge(res, -pages); -+ goto out; -+ } -+ } -+ -+ page = alloc_pages_node(node, flags, order); -+ WARN_ON(!page); -+ if (emerg) -+ *emerg = 1; -+ -+out: -+ return page; -+} -+ -+void __free_pages_reserve(struct page *page, int order, -+ struct mem_reserve *res, int emerg) -+{ -+ __free_pages(page, order); -+ mem_reserve_pages_charge(res, -(1 << order)); -+} -diff --git a/mm/slub.c b/mm/slub.c -index 056545e..ffcd315 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -2799,6 +2799,7 @@ void *__kmalloc(size_t size, gfp_t flags) - } - EXPORT_SYMBOL(__kmalloc); - -+#ifdef CONFIG_NUMA - static void *kmalloc_large_node(size_t size, gfp_t flags, int node) - { - struct page *page; -@@ -2813,7 +2814,6 @@ static void *kmalloc_large_node(size_t size, gfp_t flags, int node) - return ptr; - } - --#ifdef CONFIG_NUMA - void *__kmalloc_node(size_t size, gfp_t flags, int node) - { - struct kmem_cache *s; --- -1.7.1.1 - --- -To unsubscribe, send a message with 'unsubscribe linux-mm' in -the body to majordomo@kvack.org. For more info on Linux MM, -see: http://www.linux-mm.org/ . -Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a> diff --git a/a/content_digest b/N2/content_digest index 1eb4938..4756ff0 100644 --- a/a/content_digest +++ b/N2/content_digest @@ -16,978 +16,5 @@ " davem@davemloft.net\0" "\00:1\0" "b\0" - ">From c598d3bbb8b5e900ad0f8397b1acbe922003ac5d Mon Sep 17 00:00:00 2001\n" - "From: Xiaotian Feng <dfeng@redhat.com>\n" - "Date: Tue, 13 Jul 2010 11:01:48 +0800\n" - "Subject: [PATCH 11/30] mm: memory reserve management\n" - "\n" - "Generic reserve management code.\n" - "\n" - "It provides methods to reserve and charge. Upon this, generic alloc/free style\n" - "reserve pools could be build, which could fully replace mempool_t\n" - "functionality.\n" - "\n" - "It should also allow for a Banker's algorithm replacement of __GFP_NOFAIL.\n" - "\n" - "[dfeng@redhat.com: build fix for CONFIG_SLAB]\n" - "Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>\n" - "Signed-off-by: Suresh Jayaraman <sjayaraman@suse.de>\n" - "Signed-off-by: Xiaotian Feng <dfeng@redhat.com>\n" - "---\n" - " include/linux/reserve.h | 198 +++++++++++++++\n" - " include/linux/slab.h | 25 +-\n" - " mm/Makefile | 2 +-\n" - " mm/reserve.c | 637 +++++++++++++++++++++++++++++++++++++++++++++++\n" - " mm/slub.c | 2 +-\n" - " 5 files changed, 851 insertions(+), 13 deletions(-)\n" - " create mode 100644 include/linux/reserve.h\n" - " create mode 100644 mm/reserve.c\n" - "\n" - "diff --git a/include/linux/reserve.h b/include/linux/reserve.h\n" - "new file mode 100644\n" - "index 0000000..e1d3dbb\n" - "--- /dev/null\n" - "+++ b/include/linux/reserve.h\n" - "@@ -0,0 +1,198 @@\n" - "+/*\n" - "+ * Memory reserve management.\n" - "+ *\n" - "+ * Copyright (C) 2007-2008 Red Hat, Inc.,\n" - "+ *\t\t\t Peter Zijlstra <pzijlstr@redhat.com>\n" - "+ *\n" - "+ * This file contains the public data structure and API definitions.\n" - "+ */\n" - "+\n" - "+#ifndef _LINUX_RESERVE_H\n" - "+#define _LINUX_RESERVE_H\n" - "+\n" - "+#include <linux/list.h>\n" - "+#include <linux/spinlock.h>\n" - "+#include <linux/wait.h>\n" - "+#include <linux/slab.h>\n" - "+\n" - "+struct mem_reserve {\n" - "+\tstruct mem_reserve *parent;\n" - "+\tstruct list_head children;\n" - "+\tstruct list_head siblings;\n" - "+\n" - "+\tconst char *name;\n" - "+\n" - "+\tlong pages;\n" - "+\tlong limit;\n" - "+\tlong usage;\n" - "+\tspinlock_t lock;\t/* protects limit and usage */\n" - "+\n" - "+\twait_queue_head_t waitqueue;\n" - "+};\n" - "+\n" - "+extern struct mem_reserve mem_reserve_root;\n" - "+\n" - "+void mem_reserve_init(struct mem_reserve *res, const char *name,\n" - "+\t\t struct mem_reserve *parent);\n" - "+int mem_reserve_connect(struct mem_reserve *new_child,\n" - "+\t\t\tstruct mem_reserve *node);\n" - "+void mem_reserve_disconnect(struct mem_reserve *node);\n" - "+\n" - "+int mem_reserve_pages_set(struct mem_reserve *res, long pages);\n" - "+int mem_reserve_pages_add(struct mem_reserve *res, long pages);\n" - "+int mem_reserve_pages_charge(struct mem_reserve *res, long pages);\n" - "+\n" - "+int mem_reserve_kmalloc_set(struct mem_reserve *res, long bytes);\n" - "+int mem_reserve_kmalloc_charge(struct mem_reserve *res, long bytes);\n" - "+\n" - "+struct kmem_cache;\n" - "+\n" - "+int mem_reserve_kmem_cache_set(struct mem_reserve *res,\n" - "+\t\t\t struct kmem_cache *s,\n" - "+\t\t\t int objects);\n" - "+int mem_reserve_kmem_cache_charge(struct mem_reserve *res,\n" - "+\t\t\t\t struct kmem_cache *s, long objs);\n" - "+\n" - "+void *___kmalloc_reserve(size_t size, gfp_t flags, int node, unsigned long ip,\n" - "+\t\t\t struct mem_reserve *res, int *emerg);\n" - "+\n" - "+static inline\n" - "+void *__kmalloc_reserve(size_t size, gfp_t flags, int node, unsigned long ip,\n" - "+\t\t\tstruct mem_reserve *res, int *emerg)\n" - "+{\n" - "+\tvoid *obj;\n" - "+\n" - "+\tobj = __kmalloc_node_track_caller(size,\n" - "+\t\t\tflags | __GFP_NOMEMALLOC | __GFP_NOWARN, node, ip);\n" - "+\tif (!obj)\n" - "+\t\tobj = ___kmalloc_reserve(size, flags, node, ip, res, emerg);\n" - "+\n" - "+\treturn obj;\n" - "+}\n" - "+\n" - "+/**\n" - "+ * kmalloc_reserve() - kmalloc() and charge against @res for @emerg allocations\n" - "+ * @size - size of the requested memory region\n" - "+ * @gfp - allocation flags to use for this allocation\n" - "+ * @node - preferred memory node for this allocation\n" - "+ * @res - reserve to charge emergency allocations against\n" - "+ * @emerg - bit 0 is set when the allocation was an emergency allocation\n" - "+ *\n" - "+ * Returns NULL on failure\n" - "+ */\n" - "+#define kmalloc_reserve(size, gfp, node, res, emerg)\t\t\\\n" - "+\t__kmalloc_reserve(size, gfp, node,\t\t\t\\\n" - "+\t\t\t _RET_IP_, res, emerg)\n" - "+\n" - "+void __kfree_reserve(void *obj, struct mem_reserve *res, int emerg);\n" - "+\n" - "+/**\n" - "+ * kfree_reserve() - kfree() and uncharge against @res for @emerg allocations\n" - "+ * @obj - memory to free\n" - "+ * @res - reserve to uncharge emergency allocations from\n" - "+ * @emerg - was this an emergency allocation\n" - "+ */\n" - "+static inline\n" - "+void kfree_reserve(void *obj, struct mem_reserve *res, int emerg)\n" - "+{\n" - "+\tif (unlikely(obj && res && emerg))\n" - "+\t\t__kfree_reserve(obj, res, emerg);\n" - "+\telse\n" - "+\t\tkfree(obj);\n" - "+}\n" - "+\n" - "+void *__kmem_cache_alloc_reserve(struct kmem_cache *s, gfp_t flags, int node,\n" - "+\t\t\t\t struct mem_reserve *res, int *emerg);\n" - "+\n" - "+/**\n" - "+ * kmem_cache_alloc_reserve() - kmem_cache_alloc() and charge against @res\n" - "+ * @s - kmem_cache to allocate from\n" - "+ * @gfp - allocation flags to use for this allocation\n" - "+ * @node - preferred memory node for this allocation\n" - "+ * @res - reserve to charge emergency allocations against\n" - "+ * @emerg - bit 0 is set when the allocation was an emergency allocation\n" - "+ *\n" - "+ * Returns NULL on failure\n" - "+ */\n" - "+static inline\n" - "+void *kmem_cache_alloc_reserve(struct kmem_cache *s, gfp_t flags, int node,\n" - "+\t\t\t struct mem_reserve *res, int *emerg)\n" - "+{\n" - "+\tvoid *obj;\n" - "+\n" - "+\tobj = kmem_cache_alloc_node(s,\n" - "+\t\t\tflags | __GFP_NOMEMALLOC | __GFP_NOWARN, node);\n" - "+\tif (!obj)\n" - "+\t\tobj = __kmem_cache_alloc_reserve(s, flags, node, res, emerg);\n" - "+\n" - "+\treturn obj;\n" - "+}\n" - "+\n" - "+void __kmem_cache_free_reserve(struct kmem_cache *s, void *obj,\n" - "+\t\t\t struct mem_reserve *res, int emerg);\n" - "+\n" - "+/**\n" - "+ * kmem_cache_free_reserve() - kmem_cache_free() and uncharge against @res\n" - "+ * @s - kmem_cache to free to\n" - "+ * @obj - memory to free\n" - "+ * @res - reserve to uncharge emergency allocations from\n" - "+ * @emerg - was this an emergency allocation\n" - "+ */\n" - "+static inline\n" - "+void kmem_cache_free_reserve(struct kmem_cache *s, void *obj,\n" - "+\t\t\t struct mem_reserve *res, int emerg)\n" - "+{\n" - "+\tif (unlikely(obj && res && emerg))\n" - "+\t\t__kmem_cache_free_reserve(s, obj, res, emerg);\n" - "+\telse\n" - "+\t\tkmem_cache_free(s, obj);\n" - "+}\n" - "+\n" - "+struct page *__alloc_pages_reserve(int node, gfp_t flags, int order,\n" - "+\t\t\t\t struct mem_reserve *res, int *emerg);\n" - "+\n" - "+/**\n" - "+ * alloc_pages_reserve() - alloc_pages() and charge against @res\n" - "+ * @node - preferred memory node for this allocation\n" - "+ * @gfp - allocation flags to use for this allocation\n" - "+ * @order - page order\n" - "+ * @res - reserve to charge emergency allocations against\n" - "+ * @emerg - bit 0 is set when the allocation was an emergency allocation\n" - "+ *\n" - "+ * Returns NULL on failure\n" - "+ */\n" - "+static inline\n" - "+struct page *alloc_pages_reserve(int node, gfp_t flags, int order,\n" - "+\t\t\t\t struct mem_reserve *res, int *emerg)\n" - "+{\n" - "+\tstruct page *page;\n" - "+\n" - "+\tpage = alloc_pages_node(node,\n" - "+\t\t\tflags | __GFP_NOMEMALLOC | __GFP_NOWARN, order);\n" - "+\tif (!page)\n" - "+\t\tpage = __alloc_pages_reserve(node, flags, order, res, emerg);\n" - "+\n" - "+\treturn page;\n" - "+}\n" - "+\n" - "+void __free_pages_reserve(struct page *page, int order,\n" - "+\t\t\t struct mem_reserve *res, int emerg);\n" - "+\n" - "+/**\n" - "+ * free_pages_reserve() - __free_pages() and uncharge against @res\n" - "+ * @page - page to free\n" - "+ * @order - page order\n" - "+ * @res - reserve to uncharge emergency allocations from\n" - "+ * @emerg - was this an emergency allocation\n" - "+ */\n" - "+static inline\n" - "+void free_pages_reserve(struct page *page, int order,\n" - "+\t\t\tstruct mem_reserve *res, int emerg)\n" - "+{\n" - "+\tif (unlikely(page && res && emerg))\n" - "+\t\t__free_pages_reserve(page, order, res, emerg);\n" - "+\telse\n" - "+\t\t__free_pages(page, order);\n" - "+}\n" - "+\n" - "+#endif /* _LINUX_RESERVE_H */\n" - "diff --git a/include/linux/slab.h b/include/linux/slab.h\n" - "index b57b9ca..68195a7 100644\n" - "--- a/include/linux/slab.h\n" - "+++ b/include/linux/slab.h\n" - "@@ -272,15 +272,17 @@ static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,\n" - " * allocator where we care about the real place the memory allocation\n" - " * request comes from.\n" - " */\n" - "-#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)\n" - "+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || \\\n" - "+\t(defined(CONFIG_SLAB) && defined(CONFIG_TRACING))\n" - " extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long);\n" - "-#define kmalloc_track_caller(size, flags) \\\n" - "-\t__kmalloc_track_caller(size, flags, _RET_IP_)\n" - " #else\n" - "-#define kmalloc_track_caller(size, flags) \\\n" - "+#define __kmalloc_track_caller(size, flags, ip) \\\n" - " \t__kmalloc(size, flags)\n" - " #endif /* DEBUG_SLAB */\n" - " \n" - "+#define kmalloc_track_caller(size, flags) \\\n" - "+\t__kmalloc_track_caller(size, flags, _RET_IP_)\n" - "+\n" - " #ifdef CONFIG_NUMA\n" - " /*\n" - " * kmalloc_node_track_caller is a special version of kmalloc_node that\n" - "@@ -290,23 +292,24 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long);\n" - " * standard allocator where we care about the real place the memory\n" - " * allocation request comes from.\n" - " */\n" - "-#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)\n" - "+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB) || \\\n" - "+\t(defined(CONFIG_SLAB) && defined(CONFIG_TRACING))\n" - " extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, unsigned long);\n" - "-#define kmalloc_node_track_caller(size, flags, node) \\\n" - "-\t__kmalloc_node_track_caller(size, flags, node, \\\n" - "-\t\t\t_RET_IP_)\n" - " #else\n" - "-#define kmalloc_node_track_caller(size, flags, node) \\\n" - "+#define __kmalloc_node_track_caller(size, flags, node, ip) \\\n" - " \t__kmalloc_node(size, flags, node)\n" - " #endif\n" - " \n" - " #else /* CONFIG_NUMA */\n" - " \n" - "-#define kmalloc_node_track_caller(size, flags, node) \\\n" - "-\tkmalloc_track_caller(size, flags)\n" - "+#define __kmalloc_node_track_caller(size, flags, node, ip) \\\n" - "+\t__kmalloc_track_caller(size, flags, ip)\n" - " \n" - " #endif /* CONFIG_NUMA */\n" - " \n" - "+#define kmalloc_node_track_caller(size, flags, node) \\\n" - "+\t__kmalloc_node_track_caller(size, flags, node, \\\n" - "+\t\t\t_RET_IP_)\n" - " /*\n" - " * Shortcuts\n" - " */\n" - "diff --git a/mm/Makefile b/mm/Makefile\n" - "index 8982504..d1717bb 100644\n" - "--- a/mm/Makefile\n" - "+++ b/mm/Makefile\n" - "@@ -11,7 +11,7 @@ obj-y\t\t\t:= bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \\\n" - " \t\t\t maccess.o page_alloc.o page-writeback.o \\\n" - " \t\t\t readahead.o swap.o truncate.o vmscan.o shmem.o \\\n" - " \t\t\t prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \\\n" - "-\t\t\t page_isolation.o mm_init.o mmu_context.o \\\n" - "+\t\t\t page_isolation.o mm_init.o mmu_context.o reserve.o \\\n" - " \t\t\t $(mmu-y)\n" - " obj-y += init-mm.o\n" - " \n" - "diff --git a/mm/reserve.c b/mm/reserve.c\n" - "new file mode 100644\n" - "index 0000000..2a00d72\n" - "--- /dev/null\n" - "+++ b/mm/reserve.c\n" - "@@ -0,0 +1,637 @@\n" - "+/*\n" - "+ * Memory reserve management.\n" - "+ *\n" - "+ * Copyright (C) 2007-2008, Red Hat, Inc.,\n" - "+ *\t\t\t Peter Zijlstra <pzijlstr@redhat.com>\n" - "+ *\n" - "+ * Description:\n" - "+ *\n" - "+ * Manage a set of memory reserves.\n" - "+ *\n" - "+ * A memory reserve is a reserve for a specified number of object of specified\n" - "+ * size. Since memory is managed in pages, this reserve demand is then\n" - "+ * translated into a page unit.\n" - "+ *\n" - "+ * So each reserve has a specified object limit, an object usage count and a\n" - "+ * number of pages required to back these objects.\n" - "+ *\n" - "+ * Usage is charged against a reserve, if the charge fails, the resource must\n" - "+ * not be allocated/used.\n" - "+ *\n" - "+ * The reserves are managed in a tree, and the resource demands (pages and\n" - "+ * limit) are propagated up the tree. Obviously the object limit will be\n" - "+ * meaningless as soon as the unit starts mixing, but the required page reserve\n" - "+ * (being of one unit) is still valid at the root.\n" - "+ *\n" - "+ * It is the page demand of the root node that is used to set the global\n" - "+ * reserve (adjust_memalloc_reserve() which sets zone->pages_emerg).\n" - "+ *\n" - "+ * As long as a subtree has the same usage unit, an aggregate node can be used\n" - "+ * to charge against, instead of the leaf nodes. However, do be consistent with\n" - "+ * who is charged, resource usage is not propagated up the tree (for\n" - "+ * performance reasons).\n" - "+ */\n" - "+\n" - "+#include <linux/reserve.h>\n" - "+#include <linux/mutex.h>\n" - "+#include <linux/mmzone.h>\n" - "+#include <linux/log2.h>\n" - "+#include <linux/proc_fs.h>\n" - "+#include <linux/seq_file.h>\n" - "+#include <linux/module.h>\n" - "+#include <linux/slab.h>\n" - "+#include <linux/sched.h>\n" - "+#include \"internal.h\"\n" - "+\n" - "+static DEFINE_MUTEX(mem_reserve_mutex);\n" - "+\n" - "+/**\n" - "+ * @mem_reserve_root - the global reserve root\n" - "+ *\n" - "+ * The global reserve is empty, and has no limit unit, it merely\n" - "+ * acts as an aggregation point for reserves and an interface to\n" - "+ * adjust_memalloc_reserve().\n" - "+ */\n" - "+struct mem_reserve mem_reserve_root = {\n" - "+\t.children = LIST_HEAD_INIT(mem_reserve_root.children),\n" - "+\t.siblings = LIST_HEAD_INIT(mem_reserve_root.siblings),\n" - "+\t.name = \"total reserve\",\n" - "+\t.lock = __SPIN_LOCK_UNLOCKED(mem_reserve_root.lock),\n" - "+\t.waitqueue = __WAIT_QUEUE_HEAD_INITIALIZER(mem_reserve_root.waitqueue),\n" - "+};\n" - "+EXPORT_SYMBOL_GPL(mem_reserve_root);\n" - "+\n" - "+/**\n" - "+ * mem_reserve_init() - initialize a memory reserve object\n" - "+ * @res - the new reserve object\n" - "+ * @name - a name for this reserve\n" - "+ * @parent - when non NULL, the parent to connect to.\n" - "+ */\n" - "+void mem_reserve_init(struct mem_reserve *res, const char *name,\n" - "+\t\t struct mem_reserve *parent)\n" - "+{\n" - "+\tmemset(res, 0, sizeof(*res));\n" - "+\tINIT_LIST_HEAD(&res->children);\n" - "+\tINIT_LIST_HEAD(&res->siblings);\n" - "+\tres->name = name;\n" - "+\tspin_lock_init(&res->lock);\n" - "+\tinit_waitqueue_head(&res->waitqueue);\n" - "+\n" - "+\tif (parent)\n" - "+\t\tmem_reserve_connect(res, parent);\n" - "+}\n" - "+EXPORT_SYMBOL_GPL(mem_reserve_init);\n" - "+\n" - "+/*\n" - "+ * propagate the pages and limit changes up the (sub)tree.\n" - "+ */\n" - "+static void __calc_reserve(struct mem_reserve *res, long pages, long limit)\n" - "+{\n" - "+\tunsigned long flags;\n" - "+\n" - "+\tfor ( ; res; res = res->parent) {\n" - "+\t\tres->pages += pages;\n" - "+\n" - "+\t\tif (limit) {\n" - "+\t\t\tspin_lock_irqsave(&res->lock, flags);\n" - "+\t\t\tres->limit += limit;\n" - "+\t\t\tspin_unlock_irqrestore(&res->lock, flags);\n" - "+\t\t}\n" - "+\t}\n" - "+}\n" - "+\n" - "+/**\n" - "+ * __mem_reserve_add() - primitive to change the size of a reserve\n" - "+ * @res - reserve to change\n" - "+ * @pages - page delta\n" - "+ * @limit - usage limit delta\n" - "+ *\n" - "+ * Returns -ENOMEM when a size increase is not possible atm.\n" - "+ */\n" - "+static int __mem_reserve_add(struct mem_reserve *res, long pages, long limit)\n" - "+{\n" - "+\tint ret = 0;\n" - "+\tlong reserve;\n" - "+\n" - "+\t/*\n" - "+\t * This looks more complex than need be, that is because we handle\n" - "+\t * the case where @res isn't actually connected to mem_reserve_root.\n" - "+\t *\n" - "+\t * So, by propagating the new pages up the (sub)tree and computing\n" - "+\t * the difference in mem_reserve_root.pages we find if this action\n" - "+\t * affects the actual reserve.\n" - "+\t *\n" - "+\t * The (partial) propagation also makes that mem_reserve_connect()\n" - "+\t * needs only look at the direct child, since each disconnected\n" - "+\t * sub-tree is fully up-to-date.\n" - "+\t */\n" - "+\treserve = mem_reserve_root.pages;\n" - "+\t__calc_reserve(res, pages, 0);\n" - "+\treserve = mem_reserve_root.pages - reserve;\n" - "+\n" - "+\tif (reserve) {\n" - "+\t\tret = adjust_memalloc_reserve(reserve);\n" - "+\t\tif (ret)\n" - "+\t\t\t__calc_reserve(res, -pages, 0);\n" - "+\t}\n" - "+\n" - "+\t/*\n" - "+\t * Delay updating the limits until we've acquired the resources to\n" - "+\t * back it.\n" - "+\t */\n" - "+\tif (!ret)\n" - "+\t\t__calc_reserve(res, 0, limit);\n" - "+\n" - "+\treturn ret;\n" - "+}\n" - "+\n" - "+/**\n" - "+ * __mem_reserve_charge() - primitive to charge object usage of a reserve\n" - "+ * @res - reserve to charge\n" - "+ * @charge - size of the charge\n" - "+ *\n" - "+ * Returns non-zero on success, zero on failure.\n" - "+ */\n" - "+static\n" - "+int __mem_reserve_charge(struct mem_reserve *res, long charge)\n" - "+{\n" - "+\tunsigned long flags;\n" - "+\tint ret = 0;\n" - "+\n" - "+\tspin_lock_irqsave(&res->lock, flags);\n" - "+\tif (charge < 0 || res->usage + charge < res->limit) {\n" - "+\t\tres->usage += charge;\n" - "+\t\tif (unlikely(res->usage < 0))\n" - "+\t\t\tres->usage = 0;\n" - "+\t\tret = 1;\n" - "+\t}\n" - "+\tif (charge < 0)\n" - "+\t\twake_up_all(&res->waitqueue);\n" - "+\tspin_unlock_irqrestore(&res->lock, flags);\n" - "+\n" - "+\treturn ret;\n" - "+}\n" - "+\n" - "+/**\n" - "+ * mem_reserve_connect() - connect a reserve to another in a child-parent relation\n" - "+ * @new_child - the reserve node to connect (child)\n" - "+ * @node - the reserve node to connect to (parent)\n" - "+ *\n" - "+ * Connecting a node results in an increase of the reserve by the amount of\n" - "+ * pages in @new_child->pages if @node has a connection to mem_reserve_root.\n" - "+ *\n" - "+ * Returns -ENOMEM when the new connection would increase the reserve (parent\n" - "+ * is connected to mem_reserve_root) and there is no memory to do so.\n" - "+ *\n" - "+ * On error, the child is _NOT_ connected.\n" - "+ */\n" - "+int mem_reserve_connect(struct mem_reserve *new_child, struct mem_reserve *node)\n" - "+{\n" - "+\tint ret;\n" - "+\n" - "+\tWARN_ON(!new_child->name);\n" - "+\n" - "+\tmutex_lock(&mem_reserve_mutex);\n" - "+\tif (new_child->parent) {\n" - "+\t\tret = -EEXIST;\n" - "+\t\tgoto unlock;\n" - "+\t}\n" - "+\tnew_child->parent = node;\n" - "+\tlist_add(&new_child->siblings, &node->children);\n" - "+\tret = __mem_reserve_add(node, new_child->pages, new_child->limit);\n" - "+\tif (ret) {\n" - "+\t\tnew_child->parent = NULL;\n" - "+\t\tlist_del_init(&new_child->siblings);\n" - "+\t}\n" - "+unlock:\n" - "+\tmutex_unlock(&mem_reserve_mutex);\n" - "+\n" - "+\treturn ret;\n" - "+}\n" - "+EXPORT_SYMBOL_GPL(mem_reserve_connect);\n" - "+\n" - "+/**\n" - "+ * mem_reserve_disconnect() - sever a nodes connection to the reserve tree\n" - "+ * @node - the node to disconnect\n" - "+ *\n" - "+ * Disconnecting a node results in a reduction of the reserve by @node->pages\n" - "+ * if node had a connection to mem_reserve_root.\n" - "+ */\n" - "+void mem_reserve_disconnect(struct mem_reserve *node)\n" - "+{\n" - "+\tint ret;\n" - "+\n" - "+\tBUG_ON(!node->parent);\n" - "+\n" - "+\tmutex_lock(&mem_reserve_mutex);\n" - "+\tif (!node->parent) {\n" - "+\t\tret = -ENOENT;\n" - "+\t\tgoto unlock;\n" - "+\t}\n" - "+\tret = __mem_reserve_add(node->parent, -node->pages, -node->limit);\n" - "+\tif (!ret) {\n" - "+\t\tnode->parent = NULL;\n" - "+\t\tlist_del_init(&node->siblings);\n" - "+\t}\n" - "+unlock:\n" - "+\tmutex_unlock(&mem_reserve_mutex);\n" - "+\n" - "+\t/*\n" - "+\t * We cannot fail to shrink the reserves, can we?\n" - "+\t */\n" - "+\tWARN_ON(ret);\n" - "+}\n" - "+EXPORT_SYMBOL_GPL(mem_reserve_disconnect);\n" - "+\n" - "+#ifdef CONFIG_PROC_FS\n" - "+\n" - "+/*\n" - "+ * Simple output of the reserve tree in: /proc/reserve_info\n" - "+ * Example:\n" - "+ *\n" - "+ * localhost ~ # cat /proc/reserve_info\n" - "+ * 1:0 \"total reserve\" 6232K 0/278581\n" - "+ * 2:1 \"total network reserve\" 6232K 0/278581\n" - "+ * 3:2 \"network TX reserve\" 212K 0/53\n" - "+ * 4:3 \"protocol TX pages\" 212K 0/53\n" - "+ * 5:2 \"network RX reserve\" 6020K 0/278528\n" - "+ * 6:5 \"IPv4 route cache\" 5508K 0/16384\n" - "+ * 7:5 \"SKB data reserve\" 512K 0/262144\n" - "+ * 8:7 \"IPv4 fragment cache\" 512K 0/262144\n" - "+ */\n" - "+\n" - "+static void mem_reserve_show_item(struct seq_file *m, struct mem_reserve *res,\n" - "+\t\t\t\t unsigned int parent, unsigned int *id)\n" - "+{\n" - "+\tstruct mem_reserve *child;\n" - "+\tunsigned int my_id = ++*id;\n" - "+\n" - "+\tseq_printf(m, \"%d:%d \\\"%s\\\" %ldK %ld/%ld\\n\",\n" - "+\t\t\tmy_id, parent, res->name,\n" - "+\t\t\tres->pages << (PAGE_SHIFT - 10),\n" - "+\t\t\tres->usage, res->limit);\n" - "+\n" - "+\tlist_for_each_entry(child, &res->children, siblings)\n" - "+\t\tmem_reserve_show_item(m, child, my_id, id);\n" - "+}\n" - "+\n" - "+static int mem_reserve_show(struct seq_file *m, void *v)\n" - "+{\n" - "+\tunsigned int ident = 0;\n" - "+\n" - "+\tmutex_lock(&mem_reserve_mutex);\n" - "+\tmem_reserve_show_item(m, &mem_reserve_root, ident, &ident);\n" - "+\tmutex_unlock(&mem_reserve_mutex);\n" - "+\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+static int mem_reserve_open(struct inode *inode, struct file *file)\n" - "+{\n" - "+\treturn single_open(file, mem_reserve_show, NULL);\n" - "+}\n" - "+\n" - "+static const struct file_operations mem_reserve_opterations = {\n" - "+\t.open = mem_reserve_open,\n" - "+\t.read = seq_read,\n" - "+\t.llseek = seq_lseek,\n" - "+\t.release = single_release,\n" - "+};\n" - "+\n" - "+static __init int mem_reserve_proc_init(void)\n" - "+{\n" - "+\tproc_create(\"reserve_info\", S_IRUSR, NULL, &mem_reserve_opterations);\n" - "+\treturn 0;\n" - "+}\n" - "+\n" - "+module_init(mem_reserve_proc_init);\n" - "+\n" - "+#endif\n" - "+\n" - "+/*\n" - "+ * alloc_page helpers\n" - "+ */\n" - "+\n" - "+/**\n" - "+ * mem_reserve_pages_set() - set reserves size in pages\n" - "+ * @res - reserve to set\n" - "+ * @pages - size in pages to set it to\n" - "+ *\n" - "+ * Returns -ENOMEM when it fails to set the reserve. On failure the old size\n" - "+ * is preserved.\n" - "+ */\n" - "+int mem_reserve_pages_set(struct mem_reserve *res, long pages)\n" - "+{\n" - "+\tint ret;\n" - "+\n" - "+\tmutex_lock(&mem_reserve_mutex);\n" - "+\tpages -= res->pages;\n" - "+\tret = __mem_reserve_add(res, pages, pages * PAGE_SIZE);\n" - "+\tmutex_unlock(&mem_reserve_mutex);\n" - "+\n" - "+\treturn ret;\n" - "+}\n" - "+EXPORT_SYMBOL_GPL(mem_reserve_pages_set);\n" - "+\n" - "+/**\n" - "+ * mem_reserve_pages_add() - change the size in a relative way\n" - "+ * @res - reserve to change\n" - "+ * @pages - number of pages to add (or subtract when negative)\n" - "+ *\n" - "+ * Similar to mem_reserve_pages_set, except that the argument is relative\n" - "+ * instead of absolute.\n" - "+ *\n" - "+ * Returns -ENOMEM when it fails to increase.\n" - "+ */\n" - "+int mem_reserve_pages_add(struct mem_reserve *res, long pages)\n" - "+{\n" - "+\tint ret;\n" - "+\n" - "+\tmutex_lock(&mem_reserve_mutex);\n" - "+\tret = __mem_reserve_add(res, pages, pages * PAGE_SIZE);\n" - "+\tmutex_unlock(&mem_reserve_mutex);\n" - "+\n" - "+\treturn ret;\n" - "+}\n" - "+\n" - "+/**\n" - "+ * mem_reserve_pages_charge() - charge page usage to a reserve\n" - "+ * @res - reserve to charge\n" - "+ * @pages - size to charge\n" - "+ *\n" - "+ * Returns non-zero on success.\n" - "+ */\n" - "+int mem_reserve_pages_charge(struct mem_reserve *res, long pages)\n" - "+{\n" - "+\treturn __mem_reserve_charge(res, pages * PAGE_SIZE);\n" - "+}\n" - "+EXPORT_SYMBOL_GPL(mem_reserve_pages_charge);\n" - "+\n" - "+/*\n" - "+ * kmalloc helpers\n" - "+ */\n" - "+\n" - "+/**\n" - "+ * mem_reserve_kmalloc_set() - set this reserve to bytes worth of kmalloc\n" - "+ * @res - reserve to change\n" - "+ * @bytes - size in bytes to reserve\n" - "+ *\n" - "+ * Returns -ENOMEM on failure.\n" - "+ */\n" - "+int mem_reserve_kmalloc_set(struct mem_reserve *res, long bytes)\n" - "+{\n" - "+\tint ret;\n" - "+\tlong pages;\n" - "+\n" - "+\tmutex_lock(&mem_reserve_mutex);\n" - "+\tpages = kmalloc_estimate_bytes(GFP_ATOMIC, bytes);\n" - "+\tpages -= res->pages;\n" - "+\tbytes -= res->limit;\n" - "+\tret = __mem_reserve_add(res, pages, bytes);\n" - "+\tmutex_unlock(&mem_reserve_mutex);\n" - "+\n" - "+\treturn ret;\n" - "+}\n" - "+EXPORT_SYMBOL_GPL(mem_reserve_kmalloc_set);\n" - "+\n" - "+/**\n" - "+ * mem_reserve_kmalloc_charge() - charge bytes to a reserve\n" - "+ * @res - reserve to charge\n" - "+ * @bytes - bytes to charge\n" - "+ *\n" - "+ * Returns non-zero on success.\n" - "+ */\n" - "+int mem_reserve_kmalloc_charge(struct mem_reserve *res, long bytes)\n" - "+{\n" - "+\tif (bytes < 0)\n" - "+\t\tbytes = -roundup_pow_of_two(-bytes);\n" - "+\telse\n" - "+\t\tbytes = roundup_pow_of_two(bytes);\n" - "+\n" - "+\treturn __mem_reserve_charge(res, bytes);\n" - "+}\n" - "+EXPORT_SYMBOL_GPL(mem_reserve_kmalloc_charge);\n" - "+\n" - "+/*\n" - "+ * kmem_cache helpers\n" - "+ */\n" - "+\n" - "+/**\n" - "+ * mem_reserve_kmem_cache_set() - set reserve to @objects worth of kmem_cache_alloc of @s\n" - "+ * @res - reserve to set\n" - "+ * @s - kmem_cache to reserve from\n" - "+ * @objects - number of objects to reserve\n" - "+ *\n" - "+ * Returns -ENOMEM on failure.\n" - "+ */\n" - "+int mem_reserve_kmem_cache_set(struct mem_reserve *res, struct kmem_cache *s,\n" - "+\t\t\t int objects)\n" - "+{\n" - "+\tint ret;\n" - "+\tlong pages, bytes;\n" - "+\n" - "+\tmutex_lock(&mem_reserve_mutex);\n" - "+\tpages = kmem_alloc_estimate(s, GFP_ATOMIC, objects);\n" - "+\tpages -= res->pages;\n" - "+\tbytes = objects * kmem_cache_size(s) - res->limit;\n" - "+\tret = __mem_reserve_add(res, pages, bytes);\n" - "+\tmutex_unlock(&mem_reserve_mutex);\n" - "+\n" - "+\treturn ret;\n" - "+}\n" - "+EXPORT_SYMBOL_GPL(mem_reserve_kmem_cache_set);\n" - "+\n" - "+/**\n" - "+ * mem_reserve_kmem_cache_charge() - charge (or uncharge) usage of objs\n" - "+ * @res - reserve to charge\n" - "+ * @objs - objects to charge for\n" - "+ *\n" - "+ * Returns non-zero on success.\n" - "+ */\n" - "+int mem_reserve_kmem_cache_charge(struct mem_reserve *res, struct kmem_cache *s,\n" - "+\t\t\t\t long objs)\n" - "+{\n" - "+\treturn __mem_reserve_charge(res, objs * kmem_cache_size(s));\n" - "+}\n" - "+EXPORT_SYMBOL_GPL(mem_reserve_kmem_cache_charge);\n" - "+\n" - "+/*\n" - "+ * Alloc wrappers.\n" - "+ *\n" - "+ * Actual usage is commented in linux/reserve.h where the interface functions\n" - "+ * live. Furthermore, the code is 3 instances of the same paradigm, hence only\n" - "+ * the first contains extensive comments.\n" - "+ */\n" - "+\n" - "+/*\n" - "+ * kmalloc/kfree\n" - "+ */\n" - "+\n" - "+void *___kmalloc_reserve(size_t size, gfp_t flags, int node, unsigned long ip,\n" - "+\t\t\t struct mem_reserve *res, int *emerg)\n" - "+{\n" - "+\tvoid *obj;\n" - "+\tgfp_t gfp;\n" - "+\n" - "+\t/*\n" - "+\t * Try a regular allocation, when that fails and we're not entitled\n" - "+\t * to the reserves, fail.\n" - "+\t */\n" - "+\tgfp = flags | __GFP_NOMEMALLOC | __GFP_NOWARN;\n" - "+\tobj = __kmalloc_node_track_caller(size, gfp, node, ip);\n" - "+\n" - "+\tif (obj || !(gfp_to_alloc_flags(flags) & ALLOC_NO_WATERMARKS))\n" - "+\t\tgoto out;\n" - "+\n" - "+\t/*\n" - "+\t * If we were given a reserve to charge against, try that.\n" - "+\t */\n" - "+\tif (res && !mem_reserve_kmalloc_charge(res, size)) {\n" - "+\t\t/*\n" - "+\t\t * If we failed to charge and we're not allowed to wait for\n" - "+\t\t * it to succeed, bail.\n" - "+\t\t */\n" - "+\t\tif (!(flags & __GFP_WAIT))\n" - "+\t\t\tgoto out;\n" - "+\n" - "+\t\t/*\n" - "+\t\t * Wait for a successfull charge against the reserve. All\n" - "+\t\t * uncharge operations against this reserve will wake us up.\n" - "+\t\t */\n" - "+\t\twait_event(res->waitqueue,\n" - "+\t\t\t\tmem_reserve_kmalloc_charge(res, size));\n" - "+\n" - "+\t\t/*\n" - "+\t\t * After waiting for it, again try a regular allocation.\n" - "+\t\t * Pressure could have lifted during our sleep. If this\n" - "+\t\t * succeeds, uncharge the reserve.\n" - "+\t\t */\n" - "+\t\tobj = __kmalloc_node_track_caller(size, gfp, node, ip);\n" - "+\t\tif (obj) {\n" - "+\t\t\tmem_reserve_kmalloc_charge(res, -size);\n" - "+\t\t\tgoto out;\n" - "+\t\t}\n" - "+\t}\n" - "+\n" - "+\t/*\n" - "+\t * Regular allocation failed, and we've successfully charged our\n" - "+\t * requested usage against the reserve. Do the emergency allocation.\n" - "+\t */\n" - "+\tobj = __kmalloc_node_track_caller(size, flags, node, ip);\n" - "+\tWARN_ON(!obj);\n" - "+\tif (emerg)\n" - "+\t\t*emerg = 1;\n" - "+\n" - "+out:\n" - "+\treturn obj;\n" - "+}\n" - "+\n" - "+void __kfree_reserve(void *obj, struct mem_reserve *res, int emerg)\n" - "+{\n" - "+\t/*\n" - "+\t * ksize gives the full allocated size vs the requested size we used to\n" - "+\t * charge; however since we round up to the nearest power of two, this\n" - "+\t * should all work nicely.\n" - "+\t */\n" - "+\tsize_t size = ksize(obj);\n" - "+\n" - "+\tkfree(obj);\n" - "+\t/*\n" - "+\t * Free before uncharge, this ensures memory is actually present when\n" - "+\t * a subsequent charge succeeds.\n" - "+\t */\n" - "+\tmem_reserve_kmalloc_charge(res, -size);\n" - "+}\n" - "+\n" - "+/*\n" - "+ * kmem_cache_alloc/kmem_cache_free\n" - "+ */\n" - "+\n" - "+void *__kmem_cache_alloc_reserve(struct kmem_cache *s, gfp_t flags, int node,\n" - "+\t\t\t\t struct mem_reserve *res, int *emerg)\n" - "+{\n" - "+\tvoid *obj;\n" - "+\tgfp_t gfp;\n" - "+\n" - "+\tgfp = flags | __GFP_NOMEMALLOC | __GFP_NOWARN;\n" - "+\tobj = kmem_cache_alloc_node(s, gfp, node);\n" - "+\n" - "+\tif (obj || !(gfp_to_alloc_flags(flags) & ALLOC_NO_WATERMARKS))\n" - "+\t\tgoto out;\n" - "+\n" - "+\tif (res && !mem_reserve_kmem_cache_charge(res, s, 1)) {\n" - "+\t\tif (!(flags & __GFP_WAIT))\n" - "+\t\t\tgoto out;\n" - "+\n" - "+\t\twait_event(res->waitqueue,\n" - "+\t\t\t\tmem_reserve_kmem_cache_charge(res, s, 1));\n" - "+\n" - "+\t\tobj = kmem_cache_alloc_node(s, gfp, node);\n" - "+\t\tif (obj) {\n" - "+\t\t\tmem_reserve_kmem_cache_charge(res, s, -1);\n" - "+\t\t\tgoto out;\n" - "+\t\t}\n" - "+\t}\n" - "+\n" - "+\tobj = kmem_cache_alloc_node(s, flags, node);\n" - "+\tWARN_ON(!obj);\n" - "+\tif (emerg)\n" - "+\t\t*emerg = 1;\n" - "+\n" - "+out:\n" - "+\treturn obj;\n" - "+}\n" - "+\n" - "+void __kmem_cache_free_reserve(struct kmem_cache *s, void *obj,\n" - "+\t\t\t struct mem_reserve *res, int emerg)\n" - "+{\n" - "+\tkmem_cache_free(s, obj);\n" - "+\tmem_reserve_kmem_cache_charge(res, s, -1);\n" - "+}\n" - "+\n" - "+/*\n" - "+ * alloc_pages/free_pages\n" - "+ */\n" - "+\n" - "+struct page *__alloc_pages_reserve(int node, gfp_t flags, int order,\n" - "+\t\t\t\t struct mem_reserve *res, int *emerg)\n" - "+{\n" - "+\tstruct page *page;\n" - "+\tgfp_t gfp;\n" - "+\tlong pages = 1 << order;\n" - "+\n" - "+\tgfp = flags | __GFP_NOMEMALLOC | __GFP_NOWARN;\n" - "+\tpage = alloc_pages_node(node, gfp, order);\n" - "+\n" - "+\tif (page || !(gfp_to_alloc_flags(flags) & ALLOC_NO_WATERMARKS))\n" - "+\t\tgoto out;\n" - "+\n" - "+\tif (res && !mem_reserve_pages_charge(res, pages)) {\n" - "+\t\tif (!(flags & __GFP_WAIT))\n" - "+\t\t\tgoto out;\n" - "+\n" - "+\t\twait_event(res->waitqueue,\n" - "+\t\t\t\tmem_reserve_pages_charge(res, pages));\n" - "+\n" - "+\t\tpage = alloc_pages_node(node, gfp, order);\n" - "+\t\tif (page) {\n" - "+\t\t\tmem_reserve_pages_charge(res, -pages);\n" - "+\t\t\tgoto out;\n" - "+\t\t}\n" - "+\t}\n" - "+\n" - "+\tpage = alloc_pages_node(node, flags, order);\n" - "+\tWARN_ON(!page);\n" - "+\tif (emerg)\n" - "+\t\t*emerg = 1;\n" - "+\n" - "+out:\n" - "+\treturn page;\n" - "+}\n" - "+\n" - "+void __free_pages_reserve(struct page *page, int order,\n" - "+\t\t\t struct mem_reserve *res, int emerg)\n" - "+{\n" - "+\t__free_pages(page, order);\n" - "+\tmem_reserve_pages_charge(res, -(1 << order));\n" - "+}\n" - "diff --git a/mm/slub.c b/mm/slub.c\n" - "index 056545e..ffcd315 100644\n" - "--- a/mm/slub.c\n" - "+++ b/mm/slub.c\n" - "@@ -2799,6 +2799,7 @@ void *__kmalloc(size_t size, gfp_t flags)\n" - " }\n" - " EXPORT_SYMBOL(__kmalloc);\n" - " \n" - "+#ifdef CONFIG_NUMA\n" - " static void *kmalloc_large_node(size_t size, gfp_t flags, int node)\n" - " {\n" - " \tstruct page *page;\n" - "@@ -2813,7 +2814,6 @@ static void *kmalloc_large_node(size_t size, gfp_t flags, int node)\n" - " \treturn ptr;\n" - " }\n" - " \n" - "-#ifdef CONFIG_NUMA\n" - " void *__kmalloc_node(size_t size, gfp_t flags, int node)\n" - " {\n" - " \tstruct kmem_cache *s;\n" - "-- \n" - "1.7.1.1\n" - "\n" - "--\n" - "To unsubscribe, send a message with 'unsubscribe linux-mm' in\n" - "the body to majordomo@kvack.org. For more info on Linux MM,\n" - "see: http://www.linux-mm.org/ .\n" - "Don't email: <a href=mailto:\"dont@kvack.org\"> email@kvack.org </a>" -b97a5f82a8f2ff0d8c199276e9cb9884da2323658a0e4362b707a050da72cc29 +8e0df9e1adf093765ad89d1cc88c2395a92164e5a0a1593e83908c010689d22f
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.