diff options
Diffstat (limited to 'net/ipv4/fib_trie.c')
-rw-r--r-- | net/ipv4/fib_trie.c | 157 |
1 files changed, 73 insertions, 84 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index dea2f80e08c3..7e9031739f06 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -396,8 +396,30 @@ static void put_child(struct tnode *tn, unsigned long i, struct tnode *n) | |||
396 | rcu_assign_pointer(tn->child[i], n); | 396 | rcu_assign_pointer(tn->child[i], n); |
397 | } | 397 | } |
398 | 398 | ||
399 | static void put_child_root(struct tnode *tp, struct trie *t, | 399 | static void update_children(struct tnode *tn) |
400 | t_key key, struct tnode *n) | 400 | { |
401 | unsigned long i; | ||
402 | |||
403 | /* update all of the child parent pointers */ | ||
404 | for (i = tnode_child_length(tn); i;) { | ||
405 | struct tnode *inode = tnode_get_child(tn, --i); | ||
406 | |||
407 | if (!inode) | ||
408 | continue; | ||
409 | |||
410 | /* Either update the children of a tnode that | ||
411 | * already belongs to us or update the child | ||
412 | * to point to ourselves. | ||
413 | */ | ||
414 | if (node_parent(inode) == tn) | ||
415 | update_children(inode); | ||
416 | else | ||
417 | node_set_parent(inode, tn); | ||
418 | } | ||
419 | } | ||
420 | |||
421 | static inline void put_child_root(struct tnode *tp, struct trie *t, | ||
422 | t_key key, struct tnode *n) | ||
401 | { | 423 | { |
402 | if (tp) | 424 | if (tp) |
403 | put_child(tp, get_index(key, tp), n); | 425 | put_child(tp, get_index(key, tp), n); |
@@ -434,10 +456,35 @@ static void tnode_free(struct tnode *tn) | |||
434 | } | 456 | } |
435 | } | 457 | } |
436 | 458 | ||
459 | static void replace(struct trie *t, struct tnode *oldtnode, struct tnode *tn) | ||
460 | { | ||
461 | struct tnode *tp = node_parent(oldtnode); | ||
462 | unsigned long i; | ||
463 | |||
464 | /* setup the parent pointer out of and back into this node */ | ||
465 | NODE_INIT_PARENT(tn, tp); | ||
466 | put_child_root(tp, t, tn->key, tn); | ||
467 | |||
468 | /* update all of the child parent pointers */ | ||
469 | update_children(tn); | ||
470 | |||
471 | /* all pointers should be clean so we are done */ | ||
472 | tnode_free(oldtnode); | ||
473 | |||
474 | /* resize children now that oldtnode is freed */ | ||
475 | for (i = tnode_child_length(tn); i;) { | ||
476 | struct tnode *inode = tnode_get_child(tn, --i); | ||
477 | |||
478 | /* resize child node */ | ||
479 | if (tnode_full(tn, inode)) | ||
480 | resize(t, inode); | ||
481 | } | ||
482 | } | ||
483 | |||
437 | static int inflate(struct trie *t, struct tnode *oldtnode) | 484 | static int inflate(struct trie *t, struct tnode *oldtnode) |
438 | { | 485 | { |
439 | struct tnode *inode, *node0, *node1, *tn, *tp; | 486 | struct tnode *tn; |
440 | unsigned long i, j, k; | 487 | unsigned long i; |
441 | t_key m; | 488 | t_key m; |
442 | 489 | ||
443 | pr_debug("In inflate\n"); | 490 | pr_debug("In inflate\n"); |
@@ -446,13 +493,18 @@ static int inflate(struct trie *t, struct tnode *oldtnode) | |||
446 | if (!tn) | 493 | if (!tn) |
447 | return -ENOMEM; | 494 | return -ENOMEM; |
448 | 495 | ||
496 | /* prepare oldtnode to be freed */ | ||
497 | tnode_free_init(oldtnode); | ||
498 | |||
449 | /* Assemble all of the pointers in our cluster, in this case that | 499 | /* Assemble all of the pointers in our cluster, in this case that |
450 | * represents all of the pointers out of our allocated nodes that | 500 | * represents all of the pointers out of our allocated nodes that |
451 | * point to existing tnodes and the links between our allocated | 501 | * point to existing tnodes and the links between our allocated |
452 | * nodes. | 502 | * nodes. |
453 | */ | 503 | */ |
454 | for (i = tnode_child_length(oldtnode), m = 1u << tn->pos; i;) { | 504 | for (i = tnode_child_length(oldtnode), m = 1u << tn->pos; i;) { |
455 | inode = tnode_get_child(oldtnode, --i); | 505 | struct tnode *inode = tnode_get_child(oldtnode, --i); |
506 | struct tnode *node0, *node1; | ||
507 | unsigned long j, k; | ||
456 | 508 | ||
457 | /* An empty child */ | 509 | /* An empty child */ |
458 | if (inode == NULL) | 510 | if (inode == NULL) |
@@ -464,6 +516,9 @@ static int inflate(struct trie *t, struct tnode *oldtnode) | |||
464 | continue; | 516 | continue; |
465 | } | 517 | } |
466 | 518 | ||
519 | /* drop the node in the old tnode free list */ | ||
520 | tnode_free_append(oldtnode, inode); | ||
521 | |||
467 | /* An internal node with two children */ | 522 | /* An internal node with two children */ |
468 | if (inode->bits == 1) { | 523 | if (inode->bits == 1) { |
469 | put_child(tn, 2 * i + 1, tnode_get_child(inode, 1)); | 524 | put_child(tn, 2 * i + 1, tnode_get_child(inode, 1)); |
@@ -488,9 +543,9 @@ static int inflate(struct trie *t, struct tnode *oldtnode) | |||
488 | node1 = tnode_new(inode->key | m, inode->pos, inode->bits - 1); | 543 | node1 = tnode_new(inode->key | m, inode->pos, inode->bits - 1); |
489 | if (!node1) | 544 | if (!node1) |
490 | goto nomem; | 545 | goto nomem; |
491 | tnode_free_append(tn, node1); | 546 | node0 = tnode_new(inode->key, inode->pos, inode->bits - 1); |
492 | 547 | ||
493 | node0 = tnode_new(inode->key & ~m, inode->pos, inode->bits - 1); | 548 | tnode_free_append(tn, node1); |
494 | if (!node0) | 549 | if (!node0) |
495 | goto nomem; | 550 | goto nomem; |
496 | tnode_free_append(tn, node0); | 551 | tnode_free_append(tn, node0); |
@@ -512,53 +567,9 @@ static int inflate(struct trie *t, struct tnode *oldtnode) | |||
512 | put_child(tn, 2 * i, node0); | 567 | put_child(tn, 2 * i, node0); |
513 | } | 568 | } |
514 | 569 | ||
515 | /* setup the parent pointer into and out of this node */ | 570 | /* setup the parent pointers into and out of this node */ |
516 | tp = node_parent(oldtnode); | 571 | replace(t, oldtnode, tn); |
517 | NODE_INIT_PARENT(tn, tp); | ||
518 | put_child_root(tp, t, tn->key, tn); | ||
519 | |||
520 | /* prepare oldtnode to be freed */ | ||
521 | tnode_free_init(oldtnode); | ||
522 | |||
523 | /* update all child nodes parent pointers to route to us */ | ||
524 | for (i = tnode_child_length(oldtnode); i;) { | ||
525 | inode = tnode_get_child(oldtnode, --i); | ||
526 | |||
527 | /* A leaf or an internal node with skipped bits */ | ||
528 | if (!tnode_full(oldtnode, inode)) { | ||
529 | node_set_parent(inode, tn); | ||
530 | continue; | ||
531 | } | ||
532 | |||
533 | /* drop the node in the old tnode free list */ | ||
534 | tnode_free_append(oldtnode, inode); | ||
535 | |||
536 | /* fetch new nodes */ | ||
537 | node1 = tnode_get_child(tn, 2 * i + 1); | ||
538 | node0 = tnode_get_child(tn, 2 * i); | ||
539 | 572 | ||
540 | /* bits == 1 then node0 and node1 represent inode's children */ | ||
541 | if (inode->bits == 1) { | ||
542 | node_set_parent(node1, tn); | ||
543 | node_set_parent(node0, tn); | ||
544 | continue; | ||
545 | } | ||
546 | |||
547 | /* update parent pointers in child node's children */ | ||
548 | for (k = tnode_child_length(inode), j = k / 2; j;) { | ||
549 | node_set_parent(tnode_get_child(inode, --k), node1); | ||
550 | node_set_parent(tnode_get_child(inode, --j), node0); | ||
551 | node_set_parent(tnode_get_child(inode, --k), node1); | ||
552 | node_set_parent(tnode_get_child(inode, --j), node0); | ||
553 | } | ||
554 | |||
555 | /* resize child nodes */ | ||
556 | resize(t, node1); | ||
557 | resize(t, node0); | ||
558 | } | ||
559 | |||
560 | /* we completed without error, prepare to free old node */ | ||
561 | tnode_free(oldtnode); | ||
562 | return 0; | 573 | return 0; |
563 | nomem: | 574 | nomem: |
564 | /* all pointers should be clean so we are done */ | 575 | /* all pointers should be clean so we are done */ |
@@ -568,7 +579,7 @@ nomem: | |||
568 | 579 | ||
569 | static int halve(struct trie *t, struct tnode *oldtnode) | 580 | static int halve(struct trie *t, struct tnode *oldtnode) |
570 | { | 581 | { |
571 | struct tnode *tn, *tp, *inode, *node0, *node1; | 582 | struct tnode *tn; |
572 | unsigned long i; | 583 | unsigned long i; |
573 | 584 | ||
574 | pr_debug("In halve\n"); | 585 | pr_debug("In halve\n"); |
@@ -577,14 +588,18 @@ static int halve(struct trie *t, struct tnode *oldtnode) | |||
577 | if (!tn) | 588 | if (!tn) |
578 | return -ENOMEM; | 589 | return -ENOMEM; |
579 | 590 | ||
591 | /* prepare oldtnode to be freed */ | ||
592 | tnode_free_init(oldtnode); | ||
593 | |||
580 | /* Assemble all of the pointers in our cluster, in this case that | 594 | /* Assemble all of the pointers in our cluster, in this case that |
581 | * represents all of the pointers out of our allocated nodes that | 595 | * represents all of the pointers out of our allocated nodes that |
582 | * point to existing tnodes and the links between our allocated | 596 | * point to existing tnodes and the links between our allocated |
583 | * nodes. | 597 | * nodes. |
584 | */ | 598 | */ |
585 | for (i = tnode_child_length(oldtnode); i;) { | 599 | for (i = tnode_child_length(oldtnode); i;) { |
586 | node1 = tnode_get_child(oldtnode, --i); | 600 | struct tnode *node1 = tnode_get_child(oldtnode, --i); |
587 | node0 = tnode_get_child(oldtnode, --i); | 601 | struct tnode *node0 = tnode_get_child(oldtnode, --i); |
602 | struct tnode *inode; | ||
588 | 603 | ||
589 | /* At least one of the children is empty */ | 604 | /* At least one of the children is empty */ |
590 | if (!node1 || !node0) { | 605 | if (!node1 || !node0) { |
@@ -609,34 +624,8 @@ static int halve(struct trie *t, struct tnode *oldtnode) | |||
609 | put_child(tn, i / 2, inode); | 624 | put_child(tn, i / 2, inode); |
610 | } | 625 | } |
611 | 626 | ||
612 | /* setup the parent pointer out of and back into this node */ | 627 | /* setup the parent pointers into and out of this node */ |
613 | tp = node_parent(oldtnode); | 628 | replace(t, oldtnode, tn); |
614 | NODE_INIT_PARENT(tn, tp); | ||
615 | put_child_root(tp, t, tn->key, tn); | ||
616 | |||
617 | /* prepare oldtnode to be freed */ | ||
618 | tnode_free_init(oldtnode); | ||
619 | |||
620 | /* update all of the child parent pointers */ | ||
621 | for (i = tnode_child_length(tn); i;) { | ||
622 | inode = tnode_get_child(tn, --i); | ||
623 | |||
624 | /* only new tnodes will be considered "full" nodes */ | ||
625 | if (!tnode_full(tn, inode)) { | ||
626 | node_set_parent(inode, tn); | ||
627 | continue; | ||
628 | } | ||
629 | |||
630 | /* Two nonempty children */ | ||
631 | node_set_parent(tnode_get_child(inode, 1), inode); | ||
632 | node_set_parent(tnode_get_child(inode, 0), inode); | ||
633 | |||
634 | /* resize child node */ | ||
635 | resize(t, inode); | ||
636 | } | ||
637 | |||
638 | /* all pointers should be clean so we are done */ | ||
639 | tnode_free(oldtnode); | ||
640 | 629 | ||
641 | return 0; | 630 | return 0; |
642 | } | 631 | } |