aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorPatrick Mochel <mochel@osdl.org>2003-01-05 22:23:32 -0600
committerPatrick Mochel <mochel@osdl.org>2003-01-05 22:23:32 -0600
commit199578c4252ac04f55cc4463a0eefe0c9c1a1ff3 (patch)
tree7697d798ac5207d807ed200b0f09c723e4b65314 /lib
parentefd526efbaad0b5a6789f6c40e75c6a3bf28eae9 (diff)
parent5103c926d715ca7df1ed9fb40214f6ee995b64b6 (diff)
downloadhistory-199578c4252ac04f55cc4463a0eefe0c9c1a1ff3.tar.gz
Merge bk://linux.bkbits.net/linux-2.5
into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin
Diffstat (limited to 'lib')
-rw-r--r--lib/radix-tree.c89
1 files changed, 64 insertions, 25 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index c13196a91c7a43..dc20f8513946c1 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -20,10 +20,11 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/mempool.h>
#include <linux/module.h>
#include <linux/radix-tree.h>
+#include <linux/percpu.h>
#include <linux/slab.h>
+#include <linux/gfp.h>
#include <linux/string.h>
/*
@@ -49,18 +50,74 @@ struct radix_tree_path {
* Radix tree node cache.
*/
static kmem_cache_t *radix_tree_node_cachep;
-static mempool_t *radix_tree_node_pool;
-static inline struct radix_tree_node *
+/*
+ * Per-cpu pool of preloaded nodes
+ */
+struct radix_tree_preload {
+ int nr;
+ struct radix_tree_node *nodes[RADIX_TREE_MAX_PATH];
+};
+DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, };
+
+/*
+ * This assumes that the caller has performed appropriate preallocation, and
+ * that the caller has pinned this thread of control to the current CPU.
+ */
+static struct radix_tree_node *
radix_tree_node_alloc(struct radix_tree_root *root)
{
- return mempool_alloc(radix_tree_node_pool, root->gfp_mask);
+ struct radix_tree_node *ret;
+
+ ret = kmem_cache_alloc(radix_tree_node_cachep, root->gfp_mask);
+ if (ret == NULL && !(root->gfp_mask & __GFP_WAIT)) {
+ struct radix_tree_preload *rtp;
+
+ rtp = &__get_cpu_var(radix_tree_preloads);
+ if (rtp->nr) {
+ ret = rtp->nodes[rtp->nr - 1];
+ rtp->nodes[rtp->nr - 1] = NULL;
+ rtp->nr--;
+ }
+ }
+ return ret;
}
static inline void
radix_tree_node_free(struct radix_tree_node *node)
{
- mempool_free(node, radix_tree_node_pool);
+ kmem_cache_free(radix_tree_node_cachep, node);
+}
+
+/*
+ * Load up this CPU's radix_tree_node buffer with sufficient objects to
+ * ensure that the addition of a single element in the tree cannot fail. On
+ * success, return zero, with preemption disabled. On error, return -ENOMEM
+ * with preemption not disabled.
+ */
+int radix_tree_preload(int gfp_mask)
+{
+ struct radix_tree_preload *rtp;
+ struct radix_tree_node *node;
+ int ret = -ENOMEM;
+
+ preempt_disable();
+ rtp = &__get_cpu_var(radix_tree_preloads);
+ while (rtp->nr < ARRAY_SIZE(rtp->nodes)) {
+ preempt_enable();
+ node = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask);
+ if (node == NULL)
+ goto out;
+ preempt_disable();
+ rtp = &__get_cpu_var(radix_tree_preloads);
+ if (rtp->nr < ARRAY_SIZE(rtp->nodes))
+ rtp->nodes[rtp->nr++] = node;
+ else
+ kmem_cache_free(radix_tree_node_cachep, node);
+ }
+ ret = 0;
+out:
+ return ret;
}
/*
@@ -339,26 +396,12 @@ int radix_tree_delete(struct radix_tree_root *root, unsigned long index)
}
EXPORT_SYMBOL(radix_tree_delete);
-static void radix_tree_node_ctor(void *node, kmem_cache_t *cachep, unsigned long flags)
+static void
+radix_tree_node_ctor(void *node, kmem_cache_t *cachep, unsigned long flags)
{
memset(node, 0, sizeof(struct radix_tree_node));
}
-static void *radix_tree_node_pool_alloc(int gfp_mask, void *data)
-{
- return kmem_cache_alloc(radix_tree_node_cachep, gfp_mask);
-}
-
-static void radix_tree_node_pool_free(void *node, void *data)
-{
- kmem_cache_free(radix_tree_node_cachep, node);
-}
-
-/*
- * FIXME! 512 nodes is 200-300k of memory. This needs to be
- * scaled by the amount of available memory, and hopefully
- * reduced also.
- */
void __init radix_tree_init(void)
{
radix_tree_node_cachep = kmem_cache_create("radix_tree_node",
@@ -366,8 +409,4 @@ void __init radix_tree_init(void)
0, radix_tree_node_ctor, NULL);
if (!radix_tree_node_cachep)
panic ("Failed to create radix_tree_node cache\n");
- radix_tree_node_pool = mempool_create(512, radix_tree_node_pool_alloc,
- radix_tree_node_pool_free, NULL);
- if (!radix_tree_node_pool)
- panic ("Failed to create radix_tree_node pool\n");
}