diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-07-06 20:16:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-07-06 20:16:09 -0400 |
commit | 47a716cf0ca981b9549ec9815122ada7a0ff707c (patch) | |
tree | 9b949cce3f111c41478b6bbe404b7fdf525ef45f | |
parent | 1cc9629402b1eba0d4e21b2cc43eec9bd737f9bd (diff) | |
parent | b945d6b2554d550fe95caadc61e521c0ad71fb9c (diff) |
Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
rbtree: Undo augmented trees performance damage and regression
x86, Calgary: Limit the max PHB number to 256
-rw-r--r-- | arch/x86/kernel/pci-calgary_64.c | 4 | ||||
-rw-r--r-- | arch/x86/mm/pat_rbtree.c | 34 | ||||
-rw-r--r-- | include/linux/rbtree.h | 13 | ||||
-rw-r--r-- | lib/rbtree.c | 116 |
4 files changed, 88 insertions, 79 deletions
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 0b96b5589f08..078d4ec1a9d9 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c | |||
@@ -110,7 +110,7 @@ int use_calgary __read_mostly = 0; | |||
110 | * x3950 (PCIE): 8 chassis, 32 PHBs per chassis = 256 | 110 | * x3950 (PCIE): 8 chassis, 32 PHBs per chassis = 256 |
111 | * x3950 (PCIX): 8 chassis, 16 PHBs per chassis = 128 | 111 | * x3950 (PCIX): 8 chassis, 16 PHBs per chassis = 128 |
112 | */ | 112 | */ |
113 | #define MAX_PHB_BUS_NUM 384 | 113 | #define MAX_PHB_BUS_NUM 256 |
114 | 114 | ||
115 | #define PHBS_PER_CALGARY 4 | 115 | #define PHBS_PER_CALGARY 4 |
116 | 116 | ||
@@ -1056,8 +1056,6 @@ static int __init calgary_init_one(struct pci_dev *dev) | |||
1056 | struct iommu_table *tbl; | 1056 | struct iommu_table *tbl; |
1057 | int ret; | 1057 | int ret; |
1058 | 1058 | ||
1059 | BUG_ON(dev->bus->number >= MAX_PHB_BUS_NUM); | ||
1060 | |||
1061 | bbar = busno_to_bbar(dev->bus->number); | 1059 | bbar = busno_to_bbar(dev->bus->number); |
1062 | ret = calgary_setup_tar(dev, bbar); | 1060 | ret = calgary_setup_tar(dev, bbar); |
1063 | if (ret) | 1061 | if (ret) |
diff --git a/arch/x86/mm/pat_rbtree.c b/arch/x86/mm/pat_rbtree.c index f20eeec85a86..8acaddd0fb21 100644 --- a/arch/x86/mm/pat_rbtree.c +++ b/arch/x86/mm/pat_rbtree.c | |||
@@ -34,8 +34,7 @@ | |||
34 | * memtype_lock protects the rbtree. | 34 | * memtype_lock protects the rbtree. |
35 | */ | 35 | */ |
36 | 36 | ||
37 | static void memtype_rb_augment_cb(struct rb_node *node); | 37 | static struct rb_root memtype_rbroot = RB_ROOT; |
38 | static struct rb_root memtype_rbroot = RB_AUGMENT_ROOT(&memtype_rb_augment_cb); | ||
39 | 38 | ||
40 | static int is_node_overlap(struct memtype *node, u64 start, u64 end) | 39 | static int is_node_overlap(struct memtype *node, u64 start, u64 end) |
41 | { | 40 | { |
@@ -56,7 +55,7 @@ static u64 get_subtree_max_end(struct rb_node *node) | |||
56 | } | 55 | } |
57 | 56 | ||
58 | /* Update 'subtree_max_end' for a node, based on node and its children */ | 57 | /* Update 'subtree_max_end' for a node, based on node and its children */ |
59 | static void update_node_max_end(struct rb_node *node) | 58 | static void memtype_rb_augment_cb(struct rb_node *node, void *__unused) |
60 | { | 59 | { |
61 | struct memtype *data; | 60 | struct memtype *data; |
62 | u64 max_end, child_max_end; | 61 | u64 max_end, child_max_end; |
@@ -78,25 +77,6 @@ static void update_node_max_end(struct rb_node *node) | |||
78 | data->subtree_max_end = max_end; | 77 | data->subtree_max_end = max_end; |
79 | } | 78 | } |
80 | 79 | ||
81 | /* Update 'subtree_max_end' for a node and all its ancestors */ | ||
82 | static void update_path_max_end(struct rb_node *node) | ||
83 | { | ||
84 | u64 old_max_end, new_max_end; | ||
85 | |||
86 | while (node) { | ||
87 | struct memtype *data = container_of(node, struct memtype, rb); | ||
88 | |||
89 | old_max_end = data->subtree_max_end; | ||
90 | update_node_max_end(node); | ||
91 | new_max_end = data->subtree_max_end; | ||
92 | |||
93 | if (new_max_end == old_max_end) | ||
94 | break; | ||
95 | |||
96 | node = rb_parent(node); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | /* Find the first (lowest start addr) overlapping range from rb tree */ | 80 | /* Find the first (lowest start addr) overlapping range from rb tree */ |
101 | static struct memtype *memtype_rb_lowest_match(struct rb_root *root, | 81 | static struct memtype *memtype_rb_lowest_match(struct rb_root *root, |
102 | u64 start, u64 end) | 82 | u64 start, u64 end) |
@@ -190,12 +170,6 @@ failure: | |||
190 | return -EBUSY; | 170 | return -EBUSY; |
191 | } | 171 | } |
192 | 172 | ||
193 | static void memtype_rb_augment_cb(struct rb_node *node) | ||
194 | { | ||
195 | if (node) | ||
196 | update_path_max_end(node); | ||
197 | } | ||
198 | |||
199 | static void memtype_rb_insert(struct rb_root *root, struct memtype *newdata) | 173 | static void memtype_rb_insert(struct rb_root *root, struct memtype *newdata) |
200 | { | 174 | { |
201 | struct rb_node **node = &(root->rb_node); | 175 | struct rb_node **node = &(root->rb_node); |
@@ -213,6 +187,7 @@ static void memtype_rb_insert(struct rb_root *root, struct memtype *newdata) | |||
213 | 187 | ||
214 | rb_link_node(&newdata->rb, parent, node); | 188 | rb_link_node(&newdata->rb, parent, node); |
215 | rb_insert_color(&newdata->rb, root); | 189 | rb_insert_color(&newdata->rb, root); |
190 | rb_augment_insert(&newdata->rb, memtype_rb_augment_cb, NULL); | ||
216 | } | 191 | } |
217 | 192 | ||
218 | int rbt_memtype_check_insert(struct memtype *new, unsigned long *ret_type) | 193 | int rbt_memtype_check_insert(struct memtype *new, unsigned long *ret_type) |
@@ -234,13 +209,16 @@ int rbt_memtype_check_insert(struct memtype *new, unsigned long *ret_type) | |||
234 | 209 | ||
235 | struct memtype *rbt_memtype_erase(u64 start, u64 end) | 210 | struct memtype *rbt_memtype_erase(u64 start, u64 end) |
236 | { | 211 | { |
212 | struct rb_node *deepest; | ||
237 | struct memtype *data; | 213 | struct memtype *data; |
238 | 214 | ||
239 | data = memtype_rb_exact_match(&memtype_rbroot, start, end); | 215 | data = memtype_rb_exact_match(&memtype_rbroot, start, end); |
240 | if (!data) | 216 | if (!data) |
241 | goto out; | 217 | goto out; |
242 | 218 | ||
219 | deepest = rb_augment_erase_begin(&data->rb); | ||
243 | rb_erase(&data->rb, &memtype_rbroot); | 220 | rb_erase(&data->rb, &memtype_rbroot); |
221 | rb_augment_erase_end(deepest, memtype_rb_augment_cb, NULL); | ||
244 | out: | 222 | out: |
245 | return data; | 223 | return data; |
246 | } | 224 | } |
diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h index fe1872e5b37e..7066acb2c530 100644 --- a/include/linux/rbtree.h +++ b/include/linux/rbtree.h | |||
@@ -110,7 +110,6 @@ struct rb_node | |||
110 | struct rb_root | 110 | struct rb_root |
111 | { | 111 | { |
112 | struct rb_node *rb_node; | 112 | struct rb_node *rb_node; |
113 | void (*augment_cb)(struct rb_node *node); | ||
114 | }; | 113 | }; |
115 | 114 | ||
116 | 115 | ||
@@ -130,9 +129,7 @@ static inline void rb_set_color(struct rb_node *rb, int color) | |||
130 | rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; | 129 | rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; |
131 | } | 130 | } |
132 | 131 | ||
133 | #define RB_ROOT (struct rb_root) { NULL, NULL, } | 132 | #define RB_ROOT (struct rb_root) { NULL, } |
134 | #define RB_AUGMENT_ROOT(x) (struct rb_root) { NULL, x} | ||
135 | |||
136 | #define rb_entry(ptr, type, member) container_of(ptr, type, member) | 133 | #define rb_entry(ptr, type, member) container_of(ptr, type, member) |
137 | 134 | ||
138 | #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) | 135 | #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) |
@@ -142,6 +139,14 @@ static inline void rb_set_color(struct rb_node *rb, int color) | |||
142 | extern void rb_insert_color(struct rb_node *, struct rb_root *); | 139 | extern void rb_insert_color(struct rb_node *, struct rb_root *); |
143 | extern void rb_erase(struct rb_node *, struct rb_root *); | 140 | extern void rb_erase(struct rb_node *, struct rb_root *); |
144 | 141 | ||
142 | typedef void (*rb_augment_f)(struct rb_node *node, void *data); | ||
143 | |||
144 | extern void rb_augment_insert(struct rb_node *node, | ||
145 | rb_augment_f func, void *data); | ||
146 | extern struct rb_node *rb_augment_erase_begin(struct rb_node *node); | ||
147 | extern void rb_augment_erase_end(struct rb_node *node, | ||
148 | rb_augment_f func, void *data); | ||
149 | |||
145 | /* Find logical next and previous nodes in a tree */ | 150 | /* Find logical next and previous nodes in a tree */ |
146 | extern struct rb_node *rb_next(const struct rb_node *); | 151 | extern struct rb_node *rb_next(const struct rb_node *); |
147 | extern struct rb_node *rb_prev(const struct rb_node *); | 152 | extern struct rb_node *rb_prev(const struct rb_node *); |
diff --git a/lib/rbtree.c b/lib/rbtree.c index 15e10b1afdd2..4693f79195d3 100644 --- a/lib/rbtree.c +++ b/lib/rbtree.c | |||
@@ -44,11 +44,6 @@ static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) | |||
44 | else | 44 | else |
45 | root->rb_node = right; | 45 | root->rb_node = right; |
46 | rb_set_parent(node, right); | 46 | rb_set_parent(node, right); |
47 | |||
48 | if (root->augment_cb) { | ||
49 | root->augment_cb(node); | ||
50 | root->augment_cb(right); | ||
51 | } | ||
52 | } | 47 | } |
53 | 48 | ||
54 | static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) | 49 | static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) |
@@ -72,20 +67,12 @@ static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) | |||
72 | else | 67 | else |
73 | root->rb_node = left; | 68 | root->rb_node = left; |
74 | rb_set_parent(node, left); | 69 | rb_set_parent(node, left); |
75 | |||
76 | if (root->augment_cb) { | ||
77 | root->augment_cb(node); | ||
78 | root->augment_cb(left); | ||
79 | } | ||
80 | } | 70 | } |
81 | 71 | ||
82 | void rb_insert_color(struct rb_node *node, struct rb_root *root) | 72 | void rb_insert_color(struct rb_node *node, struct rb_root *root) |
83 | { | 73 | { |
84 | struct rb_node *parent, *gparent; | 74 | struct rb_node *parent, *gparent; |
85 | 75 | ||
86 | if (root->augment_cb) | ||
87 | root->augment_cb(node); | ||
88 | |||
89 | while ((parent = rb_parent(node)) && rb_is_red(parent)) | 76 | while ((parent = rb_parent(node)) && rb_is_red(parent)) |
90 | { | 77 | { |
91 | gparent = rb_parent(parent); | 78 | gparent = rb_parent(parent); |
@@ -240,15 +227,12 @@ void rb_erase(struct rb_node *node, struct rb_root *root) | |||
240 | else | 227 | else |
241 | { | 228 | { |
242 | struct rb_node *old = node, *left; | 229 | struct rb_node *old = node, *left; |
243 | int old_parent_cb = 0; | ||
244 | int successor_parent_cb = 0; | ||
245 | 230 | ||
246 | node = node->rb_right; | 231 | node = node->rb_right; |
247 | while ((left = node->rb_left) != NULL) | 232 | while ((left = node->rb_left) != NULL) |
248 | node = left; | 233 | node = left; |
249 | 234 | ||
250 | if (rb_parent(old)) { | 235 | if (rb_parent(old)) { |
251 | old_parent_cb = 1; | ||
252 | if (rb_parent(old)->rb_left == old) | 236 | if (rb_parent(old)->rb_left == old) |
253 | rb_parent(old)->rb_left = node; | 237 | rb_parent(old)->rb_left = node; |
254 | else | 238 | else |
@@ -263,10 +247,8 @@ void rb_erase(struct rb_node *node, struct rb_root *root) | |||
263 | if (parent == old) { | 247 | if (parent == old) { |
264 | parent = node; | 248 | parent = node; |
265 | } else { | 249 | } else { |
266 | successor_parent_cb = 1; | ||
267 | if (child) | 250 | if (child) |
268 | rb_set_parent(child, parent); | 251 | rb_set_parent(child, parent); |
269 | |||
270 | parent->rb_left = child; | 252 | parent->rb_left = child; |
271 | 253 | ||
272 | node->rb_right = old->rb_right; | 254 | node->rb_right = old->rb_right; |
@@ -277,24 +259,6 @@ void rb_erase(struct rb_node *node, struct rb_root *root) | |||
277 | node->rb_left = old->rb_left; | 259 | node->rb_left = old->rb_left; |
278 | rb_set_parent(old->rb_left, node); | 260 | rb_set_parent(old->rb_left, node); |
279 | 261 | ||
280 | if (root->augment_cb) { | ||
281 | /* | ||
282 | * Here, three different nodes can have new children. | ||
283 | * The parent of the successor node that was selected | ||
284 | * to replace the node to be erased. | ||
285 | * The node that is getting erased and is now replaced | ||
286 | * by its successor. | ||
287 | * The parent of the node getting erased-replaced. | ||
288 | */ | ||
289 | if (successor_parent_cb) | ||
290 | root->augment_cb(parent); | ||
291 | |||
292 | root->augment_cb(node); | ||
293 | |||
294 | if (old_parent_cb) | ||
295 | root->augment_cb(rb_parent(old)); | ||
296 | } | ||
297 | |||
298 | goto color; | 262 | goto color; |
299 | } | 263 | } |
300 | 264 | ||
@@ -303,19 +267,15 @@ void rb_erase(struct rb_node *node, struct rb_root *root) | |||
303 | 267 | ||
304 | if (child) | 268 | if (child) |
305 | rb_set_parent(child, parent); | 269 | rb_set_parent(child, parent); |
306 | 270 | if (parent) | |
307 | if (parent) { | 271 | { |
308 | if (parent->rb_left == node) | 272 | if (parent->rb_left == node) |
309 | parent->rb_left = child; | 273 | parent->rb_left = child; |
310 | else | 274 | else |
311 | parent->rb_right = child; | 275 | parent->rb_right = child; |
312 | |||
313 | if (root->augment_cb) | ||
314 | root->augment_cb(parent); | ||
315 | |||
316 | } else { | ||
317 | root->rb_node = child; | ||
318 | } | 276 | } |
277 | else | ||
278 | root->rb_node = child; | ||
319 | 279 | ||
320 | color: | 280 | color: |
321 | if (color == RB_BLACK) | 281 | if (color == RB_BLACK) |
@@ -323,6 +283,74 @@ void rb_erase(struct rb_node *node, struct rb_root *root) | |||
323 | } | 283 | } |
324 | EXPORT_SYMBOL(rb_erase); | 284 | EXPORT_SYMBOL(rb_erase); |
325 | 285 | ||
286 | static void rb_augment_path(struct rb_node *node, rb_augment_f func, void *data) | ||
287 | { | ||
288 | struct rb_node *parent; | ||
289 | |||
290 | up: | ||
291 | func(node, data); | ||
292 | parent = rb_parent(node); | ||
293 | if (!parent) | ||
294 | return; | ||
295 | |||
296 | if (node == parent->rb_left && parent->rb_right) | ||
297 | func(parent->rb_right, data); | ||
298 | else if (parent->rb_left) | ||
299 | func(parent->rb_left, data); | ||
300 | |||
301 | node = parent; | ||
302 | goto up; | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * after inserting @node into the tree, update the tree to account for | ||
307 | * both the new entry and any damage done by rebalance | ||
308 | */ | ||
309 | void rb_augment_insert(struct rb_node *node, rb_augment_f func, void *data) | ||
310 | { | ||
311 | if (node->rb_left) | ||
312 | node = node->rb_left; | ||
313 | else if (node->rb_right) | ||
314 | node = node->rb_right; | ||
315 | |||
316 | rb_augment_path(node, func, data); | ||
317 | } | ||
318 | |||
319 | /* | ||
320 | * before removing the node, find the deepest node on the rebalance path | ||
321 | * that will still be there after @node gets removed | ||
322 | */ | ||
323 | struct rb_node *rb_augment_erase_begin(struct rb_node *node) | ||
324 | { | ||
325 | struct rb_node *deepest; | ||
326 | |||
327 | if (!node->rb_right && !node->rb_left) | ||
328 | deepest = rb_parent(node); | ||
329 | else if (!node->rb_right) | ||
330 | deepest = node->rb_left; | ||
331 | else if (!node->rb_left) | ||
332 | deepest = node->rb_right; | ||
333 | else { | ||
334 | deepest = rb_next(node); | ||
335 | if (deepest->rb_right) | ||
336 | deepest = deepest->rb_right; | ||
337 | else if (rb_parent(deepest) != node) | ||
338 | deepest = rb_parent(deepest); | ||
339 | } | ||
340 | |||
341 | return deepest; | ||
342 | } | ||
343 | |||
344 | /* | ||
345 | * after removal, update the tree to account for the removed entry | ||
346 | * and any rebalance damage. | ||
347 | */ | ||
348 | void rb_augment_erase_end(struct rb_node *node, rb_augment_f func, void *data) | ||
349 | { | ||
350 | if (node) | ||
351 | rb_augment_path(node, func, data); | ||
352 | } | ||
353 | |||
326 | /* | 354 | /* |
327 | * This function returns the first node (in sort order) of the tree. | 355 | * This function returns the first node (in sort order) of the tree. |
328 | */ | 356 | */ |