diff options
| author | Andrew Morton <akpm@digeo.com> | 2003-01-05 03:51:21 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2003-01-05 03:51:21 -0800 |
| commit | 9fb6fde975800f1275d466775913b175cd039044 (patch) | |
| tree | 13c504c2db4b116ec88359237cd0874a7c561f25 /include/linux | |
| parent | aaf2ef19a8230e93cfca948738bc3990a589b8fb (diff) | |
[PATCH] infrastructure for handling radix_tree_node allocation
radix_tree_node_alloc() uses GFP_ATOMIC, under spinlocking. If the
allocation fails then userspace sees ENOMEM and application failure occurs.
A single add_to_page_cache() will require up to six radix_tree_nodes on
32-bit machines, twice this on 64-bit machines (quadruple the worst-case
storage on 64-bit).
My approach to solving this problem is to create a per-cpu pool of
preallocated radix_tree_nodes, private to the radix-tree code.
The radix-tree user will call the new radix-tree API function
radix_tree_preload() to ensure that this pool has sufficient nodes to cover
the worst-case. radix_tree_preload() should be called outside locks, with
GFP_KERNEL so that it can run page reclaim.
If it succeeds, radix_tree_preload() will return with preemption disabled so
that the per-cpu radix_tree_node pool is protected. The user must call
radix_tree_preload_end() to terminate the transaction.
In the common case, the per-cpu pools will never be touched:
radix_tree_insert() will only dip into the pool if kmem_cache_alloc() fails.
The pools will remain full at all times. This is to optimise the fastpath -
it is just a few instructions.
This patch also removes the now-unneeded radix-tree mempool. This saves 130
kbytes of permanently allocated kernel memory. 260k on 64-bit platforms.
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/radix-tree.h | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index 4e58eb79abeb..f4a78d52b5ce 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -19,6 +19,8 @@ #ifndef _LINUX_RADIX_TREE_H #define _LINUX_RADIX_TREE_H +#include <linux/preempt.h> + struct radix_tree_node; struct radix_tree_root { @@ -45,5 +47,11 @@ extern int radix_tree_delete(struct radix_tree_root *, unsigned long); extern unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items); +int radix_tree_preload(int gfp_mask); + +static inline void radix_tree_preload_end(void) +{ + preempt_enable(); +} #endif /* _LINUX_RADIX_TREE_H */ |
