Commit 106a98c4 authored by Werner Almesberger's avatar Werner Almesberger Committed by Linus Torvalds

[PATCH] prio_tree: generalization

Export prio_tree functions such that they can be used by other subsystems than
only VMAs.  Also adds a mode to prio_tree to use it with keys explicitly
included in the prio_tree meta-data.

The plan is to also consider converting VMAs to use explicit keys, so that the
old "raw" mode can be removed.
Signed-off-by: default avatarWerner Almesberger <werner@almesberger.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 14c1f34c
...@@ -201,7 +201,7 @@ void inode_init_once(struct inode *inode) ...@@ -201,7 +201,7 @@ void inode_init_once(struct inode *inode)
atomic_set(&inode->i_data.truncate_count, 0); atomic_set(&inode->i_data.truncate_count, 0);
INIT_LIST_HEAD(&inode->i_data.private_list); INIT_LIST_HEAD(&inode->i_data.private_list);
spin_lock_init(&inode->i_data.private_lock); spin_lock_init(&inode->i_data.private_lock);
INIT_PRIO_TREE_ROOT(&inode->i_data.i_mmap); INIT_RAW_PRIO_TREE_ROOT(&inode->i_data.i_mmap);
INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear); INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear);
spin_lock_init(&inode->i_lock); spin_lock_init(&inode->i_lock);
i_size_ordered_init(inode); i_size_ordered_init(inode);
......
...@@ -85,7 +85,7 @@ struct vm_area_struct { ...@@ -85,7 +85,7 @@ struct vm_area_struct {
struct vm_area_struct *head; struct vm_area_struct *head;
} vm_set; } vm_set;
struct prio_tree_node prio_tree_node; struct raw_prio_tree_node prio_tree_node;
} shared; } shared;
/* /*
......
#ifndef _LINUX_PRIO_TREE_H #ifndef _LINUX_PRIO_TREE_H
#define _LINUX_PRIO_TREE_H #define _LINUX_PRIO_TREE_H
/*
* K&R 2nd ed. A8.3 somewhat obliquely hints that initial sequences of struct
* fields with identical types should end up at the same location. We'll use
* this until we can scrap struct raw_prio_tree_node.
*
* Note: all this could be done more elegantly by using unnamed union/struct
* fields. However, gcc 2.95.3 and apparently also gcc 3.0.4 don't support this
* language extension.
*/
struct raw_prio_tree_node {
struct prio_tree_node *left;
struct prio_tree_node *right;
struct prio_tree_node *parent;
};
struct prio_tree_node { struct prio_tree_node {
struct prio_tree_node *left; struct prio_tree_node *left;
struct prio_tree_node *right; struct prio_tree_node *right;
struct prio_tree_node *parent; struct prio_tree_node *parent;
unsigned long start;
unsigned long last; /* last location _in_ interval */
}; };
struct prio_tree_root { struct prio_tree_root {
struct prio_tree_node *prio_tree_node; struct prio_tree_node *prio_tree_node;
unsigned int index_bits; unsigned short index_bits;
unsigned short raw;
/*
* 0: nodes are of type struct prio_tree_node
* 1: nodes are of type raw_prio_tree_node
*/
}; };
struct prio_tree_iter { struct prio_tree_iter {
...@@ -32,12 +55,16 @@ static inline void prio_tree_iter_init(struct prio_tree_iter *iter, ...@@ -32,12 +55,16 @@ static inline void prio_tree_iter_init(struct prio_tree_iter *iter,
iter->cur = NULL; iter->cur = NULL;
} }
#define INIT_PRIO_TREE_ROOT(ptr) \ #define __INIT_PRIO_TREE_ROOT(ptr, _raw) \
do { \ do { \
(ptr)->prio_tree_node = NULL; \ (ptr)->prio_tree_node = NULL; \
(ptr)->index_bits = 1; \ (ptr)->index_bits = 1; \
(ptr)->raw = (_raw); \
} while (0) } while (0)
#define INIT_PRIO_TREE_ROOT(ptr) __INIT_PRIO_TREE_ROOT(ptr, 0)
#define INIT_RAW_PRIO_TREE_ROOT(ptr) __INIT_PRIO_TREE_ROOT(ptr, 1)
#define INIT_PRIO_TREE_NODE(ptr) \ #define INIT_PRIO_TREE_NODE(ptr) \
do { \ do { \
(ptr)->left = (ptr)->right = (ptr)->parent = (ptr); \ (ptr)->left = (ptr)->right = (ptr)->parent = (ptr); \
...@@ -74,4 +101,20 @@ static inline int prio_tree_right_empty(const struct prio_tree_node *node) ...@@ -74,4 +101,20 @@ static inline int prio_tree_right_empty(const struct prio_tree_node *node)
return node->right == node; return node->right == node;
} }
struct prio_tree_node *prio_tree_replace(struct prio_tree_root *root,
struct prio_tree_node *old, struct prio_tree_node *node);
struct prio_tree_node *prio_tree_insert(struct prio_tree_root *root,
struct prio_tree_node *node);
void prio_tree_remove(struct prio_tree_root *root, struct prio_tree_node *node);
struct prio_tree_node *prio_tree_next(struct prio_tree_iter *iter);
#define raw_prio_tree_replace(root, old, node) \
prio_tree_replace(root, (struct prio_tree_node *) (old), \
(struct prio_tree_node *) (node))
#define raw_prio_tree_insert(root, node) \
prio_tree_insert(root, (struct prio_tree_node *) (node))
#define raw_prio_tree_remove(root, node) \
prio_tree_remove(root, (struct prio_tree_node *) (node))
#endif /* _LINUX_PRIO_TREE_H */ #endif /* _LINUX_PRIO_TREE_H */
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/prio_tree.h> #include <linux/prio_tree.h>
...@@ -49,18 +48,23 @@ ...@@ -49,18 +48,23 @@
/* avoid overflow */ /* avoid overflow */
#define HEAP_INDEX(vma) ((vma)->vm_pgoff + (VMA_SIZE(vma) - 1)) #define HEAP_INDEX(vma) ((vma)->vm_pgoff + (VMA_SIZE(vma) - 1))
#define GET_INDEX_VMA(vma, radix, heap) \
do { \
radix = RADIX_INDEX(vma); \
heap = HEAP_INDEX(vma); \
} while (0)
#define GET_INDEX(node, radix, heap) \ static void get_index(const struct prio_tree_root *root,
do { \ const struct prio_tree_node *node,
struct vm_area_struct *__tmp = \ unsigned long *radix, unsigned long *heap)
prio_tree_entry(node, struct vm_area_struct, shared.prio_tree_node);\ {
GET_INDEX_VMA(__tmp, radix, heap); \ if (root->raw) {
} while (0) struct vm_area_struct *vma = prio_tree_entry(
node, struct vm_area_struct, shared.prio_tree_node);
*radix = RADIX_INDEX(vma);
*heap = HEAP_INDEX(vma);
}
else {
*radix = node->start;
*heap = node->last;
}
}
static unsigned long index_bits_to_maxindex[BITS_PER_LONG]; static unsigned long index_bits_to_maxindex[BITS_PER_LONG];
...@@ -81,8 +85,6 @@ static inline unsigned long prio_tree_maxindex(unsigned int bits) ...@@ -81,8 +85,6 @@ static inline unsigned long prio_tree_maxindex(unsigned int bits)
return index_bits_to_maxindex[bits - 1]; return index_bits_to_maxindex[bits - 1];
} }
static void prio_tree_remove(struct prio_tree_root *, struct prio_tree_node *);
/* /*
* Extend a priority search tree so that it can store a node with heap_index * Extend a priority search tree so that it can store a node with heap_index
* max_heap_index. In the worst case, this algorithm takes O((log n)^2). * max_heap_index. In the worst case, this algorithm takes O((log n)^2).
...@@ -138,7 +140,7 @@ static struct prio_tree_node *prio_tree_expand(struct prio_tree_root *root, ...@@ -138,7 +140,7 @@ static struct prio_tree_node *prio_tree_expand(struct prio_tree_root *root,
/* /*
* Replace a prio_tree_node with a new node and return the old node * Replace a prio_tree_node with a new node and return the old node
*/ */
static struct prio_tree_node *prio_tree_replace(struct prio_tree_root *root, struct prio_tree_node *prio_tree_replace(struct prio_tree_root *root,
struct prio_tree_node *old, struct prio_tree_node *node) struct prio_tree_node *old, struct prio_tree_node *node)
{ {
INIT_PRIO_TREE_NODE(node); INIT_PRIO_TREE_NODE(node);
...@@ -182,7 +184,7 @@ static struct prio_tree_node *prio_tree_replace(struct prio_tree_root *root, ...@@ -182,7 +184,7 @@ static struct prio_tree_node *prio_tree_replace(struct prio_tree_root *root,
* the tree, then returns the address of the prior node. Otherwise, inserts * the tree, then returns the address of the prior node. Otherwise, inserts
* @node into the tree and returns @node. * @node into the tree and returns @node.
*/ */
static struct prio_tree_node *prio_tree_insert(struct prio_tree_root *root, struct prio_tree_node *prio_tree_insert(struct prio_tree_root *root,
struct prio_tree_node *node) struct prio_tree_node *node)
{ {
struct prio_tree_node *cur, *res = node; struct prio_tree_node *cur, *res = node;
...@@ -190,7 +192,7 @@ static struct prio_tree_node *prio_tree_insert(struct prio_tree_root *root, ...@@ -190,7 +192,7 @@ static struct prio_tree_node *prio_tree_insert(struct prio_tree_root *root,
unsigned long r_index, h_index, index, mask; unsigned long r_index, h_index, index, mask;
int size_flag = 0; int size_flag = 0;
GET_INDEX(node, radix_index, heap_index); get_index(root, node, &radix_index, &heap_index);
if (prio_tree_empty(root) || if (prio_tree_empty(root) ||
heap_index > prio_tree_maxindex(root->index_bits)) heap_index > prio_tree_maxindex(root->index_bits))
...@@ -200,7 +202,7 @@ static struct prio_tree_node *prio_tree_insert(struct prio_tree_root *root, ...@@ -200,7 +202,7 @@ static struct prio_tree_node *prio_tree_insert(struct prio_tree_root *root,
mask = 1UL << (root->index_bits - 1); mask = 1UL << (root->index_bits - 1);
while (mask) { while (mask) {
GET_INDEX(cur, r_index, h_index); get_index(root, cur, &r_index, &h_index);
if (r_index == radix_index && h_index == heap_index) if (r_index == radix_index && h_index == heap_index)
return cur; return cur;
...@@ -259,8 +261,7 @@ static struct prio_tree_node *prio_tree_insert(struct prio_tree_root *root, ...@@ -259,8 +261,7 @@ static struct prio_tree_node *prio_tree_insert(struct prio_tree_root *root,
* algorithm takes O(log n) time where 'log n' is the number of bits required * algorithm takes O(log n) time where 'log n' is the number of bits required
* to represent the maximum heap_index. * to represent the maximum heap_index.
*/ */
static void prio_tree_remove(struct prio_tree_root *root, void prio_tree_remove(struct prio_tree_root *root, struct prio_tree_node *node)
struct prio_tree_node *node)
{ {
struct prio_tree_node *cur; struct prio_tree_node *cur;
unsigned long r_index, h_index_right, h_index_left; unsigned long r_index, h_index_right, h_index_left;
...@@ -269,14 +270,14 @@ static void prio_tree_remove(struct prio_tree_root *root, ...@@ -269,14 +270,14 @@ static void prio_tree_remove(struct prio_tree_root *root,
while (!prio_tree_left_empty(cur) || !prio_tree_right_empty(cur)) { while (!prio_tree_left_empty(cur) || !prio_tree_right_empty(cur)) {
if (!prio_tree_left_empty(cur)) if (!prio_tree_left_empty(cur))
GET_INDEX(cur->left, r_index, h_index_left); get_index(root, cur->left, &r_index, &h_index_left);
else { else {
cur = cur->right; cur = cur->right;
continue; continue;
} }
if (!prio_tree_right_empty(cur)) if (!prio_tree_right_empty(cur))
GET_INDEX(cur->right, r_index, h_index_right); get_index(root, cur->right, &r_index, &h_index_right);
else { else {
cur = cur->left; cur = cur->left;
continue; continue;
...@@ -291,7 +292,7 @@ static void prio_tree_remove(struct prio_tree_root *root, ...@@ -291,7 +292,7 @@ static void prio_tree_remove(struct prio_tree_root *root,
if (prio_tree_root(cur)) { if (prio_tree_root(cur)) {
BUG_ON(root->prio_tree_node != cur); BUG_ON(root->prio_tree_node != cur);
INIT_PRIO_TREE_ROOT(root); __INIT_PRIO_TREE_ROOT(root, root->raw);
return; return;
} }
...@@ -318,7 +319,7 @@ static struct prio_tree_node *prio_tree_left(struct prio_tree_iter *iter, ...@@ -318,7 +319,7 @@ static struct prio_tree_node *prio_tree_left(struct prio_tree_iter *iter,
if (prio_tree_left_empty(iter->cur)) if (prio_tree_left_empty(iter->cur))
return NULL; return NULL;
GET_INDEX(iter->cur->left, *r_index, *h_index); get_index(iter->root, iter->cur->left, r_index, h_index);
if (iter->r_index <= *h_index) { if (iter->r_index <= *h_index) {
iter->cur = iter->cur->left; iter->cur = iter->cur->left;
...@@ -359,7 +360,7 @@ static struct prio_tree_node *prio_tree_right(struct prio_tree_iter *iter, ...@@ -359,7 +360,7 @@ static struct prio_tree_node *prio_tree_right(struct prio_tree_iter *iter,
if (iter->h_index < value) if (iter->h_index < value)
return NULL; return NULL;
GET_INDEX(iter->cur->right, *r_index, *h_index); get_index(iter->root, iter->cur->right, r_index, h_index);
if (iter->r_index <= *h_index) { if (iter->r_index <= *h_index) {
iter->cur = iter->cur->right; iter->cur = iter->cur->right;
...@@ -425,7 +426,7 @@ static struct prio_tree_node *prio_tree_first(struct prio_tree_iter *iter) ...@@ -425,7 +426,7 @@ static struct prio_tree_node *prio_tree_first(struct prio_tree_iter *iter)
if (prio_tree_empty(root)) if (prio_tree_empty(root))
return NULL; return NULL;
GET_INDEX(root->prio_tree_node, r_index, h_index); get_index(root, root->prio_tree_node, &r_index, &h_index);
if (iter->r_index > h_index) if (iter->r_index > h_index)
return NULL; return NULL;
...@@ -453,7 +454,7 @@ static struct prio_tree_node *prio_tree_first(struct prio_tree_iter *iter) ...@@ -453,7 +454,7 @@ static struct prio_tree_node *prio_tree_first(struct prio_tree_iter *iter)
* *
* Get the next prio_tree_node that overlaps with the input interval in iter * Get the next prio_tree_node that overlaps with the input interval in iter
*/ */
static struct prio_tree_node *prio_tree_next(struct prio_tree_iter *iter) struct prio_tree_node *prio_tree_next(struct prio_tree_iter *iter)
{ {
unsigned long r_index, h_index; unsigned long r_index, h_index;
...@@ -554,8 +555,8 @@ void vma_prio_tree_insert(struct vm_area_struct *vma, ...@@ -554,8 +555,8 @@ void vma_prio_tree_insert(struct vm_area_struct *vma,
vma->shared.vm_set.head = NULL; vma->shared.vm_set.head = NULL;
ptr = prio_tree_insert(root, &vma->shared.prio_tree_node); ptr = raw_prio_tree_insert(root, &vma->shared.prio_tree_node);
if (ptr != &vma->shared.prio_tree_node) { if (ptr != (struct prio_tree_node *) &vma->shared.prio_tree_node) {
old = prio_tree_entry(ptr, struct vm_area_struct, old = prio_tree_entry(ptr, struct vm_area_struct,
shared.prio_tree_node); shared.prio_tree_node);
vma_prio_tree_add(vma, old); vma_prio_tree_add(vma, old);
...@@ -571,7 +572,7 @@ void vma_prio_tree_remove(struct vm_area_struct *vma, ...@@ -571,7 +572,7 @@ void vma_prio_tree_remove(struct vm_area_struct *vma,
if (!vma->shared.vm_set.parent) if (!vma->shared.vm_set.parent)
list_del_init(&vma->shared.vm_set.list); list_del_init(&vma->shared.vm_set.list);
else else
prio_tree_remove(root, &vma->shared.prio_tree_node); raw_prio_tree_remove(root, &vma->shared.prio_tree_node);
} else { } else {
/* Leave this BUG_ON till prio_tree patch stabilizes */ /* Leave this BUG_ON till prio_tree patch stabilizes */
BUG_ON(vma->shared.vm_set.head->shared.vm_set.head != vma); BUG_ON(vma->shared.vm_set.head->shared.vm_set.head != vma);
...@@ -586,7 +587,7 @@ void vma_prio_tree_remove(struct vm_area_struct *vma, ...@@ -586,7 +587,7 @@ void vma_prio_tree_remove(struct vm_area_struct *vma,
} else } else
new_head = NULL; new_head = NULL;
prio_tree_replace(root, &vma->shared.prio_tree_node, raw_prio_tree_replace(root, &vma->shared.prio_tree_node,
&head->shared.prio_tree_node); &head->shared.prio_tree_node);
head->shared.vm_set.head = new_head; head->shared.vm_set.head = new_head;
if (new_head) if (new_head)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment