|
@@ -21,6 +21,7 @@
|
|
#include <linux/debugobjects.h>
|
|
#include <linux/debugobjects.h>
|
|
#include <linux/kallsyms.h>
|
|
#include <linux/kallsyms.h>
|
|
#include <linux/list.h>
|
|
#include <linux/list.h>
|
|
|
|
+#include <linux/notifier.h>
|
|
#include <linux/rbtree.h>
|
|
#include <linux/rbtree.h>
|
|
#include <linux/radix-tree.h>
|
|
#include <linux/radix-tree.h>
|
|
#include <linux/rcupdate.h>
|
|
#include <linux/rcupdate.h>
|
|
@@ -344,6 +345,8 @@ static void __insert_vmap_area(struct vmap_area *va)
|
|
|
|
|
|
static void purge_vmap_area_lazy(void);
|
|
static void purge_vmap_area_lazy(void);
|
|
|
|
|
|
|
|
+static BLOCKING_NOTIFIER_HEAD(vmap_notify_list);
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Allocate a region of KVA of the specified size and alignment, within the
|
|
* Allocate a region of KVA of the specified size and alignment, within the
|
|
* vstart and vend.
|
|
* vstart and vend.
|
|
@@ -363,6 +366,8 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
|
|
BUG_ON(offset_in_page(size));
|
|
BUG_ON(offset_in_page(size));
|
|
BUG_ON(!is_power_of_2(align));
|
|
BUG_ON(!is_power_of_2(align));
|
|
|
|
|
|
|
|
+ might_sleep_if(gfpflags_allow_blocking(gfp_mask));
|
|
|
|
+
|
|
va = kmalloc_node(sizeof(struct vmap_area),
|
|
va = kmalloc_node(sizeof(struct vmap_area),
|
|
gfp_mask & GFP_RECLAIM_MASK, node);
|
|
gfp_mask & GFP_RECLAIM_MASK, node);
|
|
if (unlikely(!va))
|
|
if (unlikely(!va))
|
|
@@ -468,6 +473,16 @@ overflow:
|
|
purged = 1;
|
|
purged = 1;
|
|
goto retry;
|
|
goto retry;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (gfpflags_allow_blocking(gfp_mask)) {
|
|
|
|
+ unsigned long freed = 0;
|
|
|
|
+ blocking_notifier_call_chain(&vmap_notify_list, 0, &freed);
|
|
|
|
+ if (freed > 0) {
|
|
|
|
+ purged = 0;
|
|
|
|
+ goto retry;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
if (printk_ratelimit())
|
|
if (printk_ratelimit())
|
|
pr_warn("vmap allocation for size %lu failed: "
|
|
pr_warn("vmap allocation for size %lu failed: "
|
|
"use vmalloc=<size> to increase size.\n", size);
|
|
"use vmalloc=<size> to increase size.\n", size);
|
|
@@ -475,6 +490,18 @@ overflow:
|
|
return ERR_PTR(-EBUSY);
|
|
return ERR_PTR(-EBUSY);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+int register_vmap_purge_notifier(struct notifier_block *nb)
|
|
|
|
+{
|
|
|
|
+ return blocking_notifier_chain_register(&vmap_notify_list, nb);
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(register_vmap_purge_notifier);
|
|
|
|
+
|
|
|
|
+int unregister_vmap_purge_notifier(struct notifier_block *nb)
|
|
|
|
+{
|
|
|
|
+ return blocking_notifier_chain_unregister(&vmap_notify_list, nb);
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(unregister_vmap_purge_notifier);
|
|
|
|
+
|
|
static void __free_vmap_area(struct vmap_area *va)
|
|
static void __free_vmap_area(struct vmap_area *va)
|
|
{
|
|
{
|
|
BUG_ON(RB_EMPTY_NODE(&va->rb_node));
|
|
BUG_ON(RB_EMPTY_NODE(&va->rb_node));
|