* properly format/comment all patches * merge debloat patches * merge Kconfig patches * merge swconfig patches * merge hotplug patches * drop 200-fix_localversion.patch - upstream * drop 222-arm_zimage_none.patch - unused * drop 252-mv_cesa_depends.patch - no longer required * drop 410-mtd-move-forward-declaration-of-struct-mtd_info.patch - unused * drop 661-fq_codel_keep_dropped_stats.patch - outdated * drop 702-phy_add_aneg_done_function.patch - upstream * drop 840-rtc7301.patch - unused * drop 841-rtc_pt7c4338.patch - upstream * drop 921-use_preinit_as_init.patch - unused * drop spio-gpio-old and gpio-mmc - unused Signed-off-by: John Crispin <john@phrozen.org>
		
			
				
	
	
		
			277 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			277 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From: Alexander Duyck <alexander.h.duyck@redhat.com>
 | |
| Date: Wed, 31 Dec 2014 10:56:06 -0800
 | |
| Subject: [PATCH] fib_trie: Optimize fib_table_insert
 | |
| 
 | |
| This patch updates the fib_table_insert function to take advantage of the
 | |
| changes made to improve the performance of fib_table_lookup.  As a result
 | |
| the code should be smaller and run faster then the original.
 | |
| 
 | |
| Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
 | |
| Signed-off-by: David S. Miller <davem@davemloft.net>
 | |
| ---
 | |
| 
 | |
| --- a/net/ipv4/fib_trie.c
 | |
| +++ b/net/ipv4/fib_trie.c
 | |
| @@ -222,31 +222,6 @@ static inline t_key tkey_extract_bits(t_
 | |
|  		return 0;
 | |
|  }
 | |
|  
 | |
| -static inline int tkey_equals(t_key a, t_key b)
 | |
| -{
 | |
| -	return a == b;
 | |
| -}
 | |
| -
 | |
| -static inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b)
 | |
| -{
 | |
| -	if (bits == 0 || offset >= KEYLENGTH)
 | |
| -		return 1;
 | |
| -	bits = bits > KEYLENGTH ? KEYLENGTH : bits;
 | |
| -	return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0;
 | |
| -}
 | |
| -
 | |
| -static inline int tkey_mismatch(t_key a, int offset, t_key b)
 | |
| -{
 | |
| -	t_key diff = a ^ b;
 | |
| -	int i = offset;
 | |
| -
 | |
| -	if (!diff)
 | |
| -		return 0;
 | |
| -	while ((diff << i) >> (KEYLENGTH-1) == 0)
 | |
| -		i++;
 | |
| -	return i;
 | |
| -}
 | |
| -
 | |
|  /*
 | |
|    To understand this stuff, an understanding of keys and all their bits is
 | |
|    necessary. Every node in the trie has a key associated with it, but not
 | |
| @@ -485,6 +460,15 @@ static void tnode_put_child_reorg(struct
 | |
|  	rcu_assign_pointer(tn->child[i], n);
 | |
|  }
 | |
|  
 | |
| +static void put_child_root(struct tnode *tp, struct trie *t,
 | |
| +			   t_key key, struct tnode *n)
 | |
| +{
 | |
| +	if (tp)
 | |
| +		put_child(tp, get_index(key, tp), n);
 | |
| +	else
 | |
| +		rcu_assign_pointer(t->trie, n);
 | |
| +}
 | |
| +
 | |
|  #define MAX_WORK 10
 | |
|  static struct tnode *resize(struct trie *t, struct tnode *tn)
 | |
|  {
 | |
| @@ -959,138 +943,100 @@ static void trie_rebalance(struct trie *
 | |
|  
 | |
|  static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen)
 | |
|  {
 | |
| -	int pos, newpos;
 | |
| -	struct tnode *tp = NULL, *tn = NULL;
 | |
| -	struct tnode *n;
 | |
| -	struct tnode *l;
 | |
| -	int missbit;
 | |
|  	struct list_head *fa_head = NULL;
 | |
| +	struct tnode *l, *n, *tp = NULL;
 | |
|  	struct leaf_info *li;
 | |
| -	t_key cindex;
 | |
|  
 | |
| -	pos = 0;
 | |
| +	li = leaf_info_new(plen);
 | |
| +	if (!li)
 | |
| +		return NULL;
 | |
| +	fa_head = &li->falh;
 | |
| +
 | |
|  	n = rtnl_dereference(t->trie);
 | |
|  
 | |
|  	/* If we point to NULL, stop. Either the tree is empty and we should
 | |
|  	 * just put a new leaf in if, or we have reached an empty child slot,
 | |
|  	 * and we should just put our new leaf in that.
 | |
| -	 * If we point to a T_TNODE, check if it matches our key. Note that
 | |
| -	 * a T_TNODE might be skipping any number of bits - its 'pos' need
 | |
| -	 * not be the parent's 'pos'+'bits'!
 | |
| -	 *
 | |
| -	 * If it does match the current key, get pos/bits from it, extract
 | |
| -	 * the index from our key, push the T_TNODE and walk the tree.
 | |
| -	 *
 | |
| -	 * If it doesn't, we have to replace it with a new T_TNODE.
 | |
|  	 *
 | |
| -	 * If we point to a T_LEAF, it might or might not have the same key
 | |
| -	 * as we do. If it does, just change the value, update the T_LEAF's
 | |
| -	 * value, and return it.
 | |
| -	 * If it doesn't, we need to replace it with a T_TNODE.
 | |
| +	 * If we hit a node with a key that does't match then we should stop
 | |
| +	 * and create a new tnode to replace that node and insert ourselves
 | |
| +	 * and the other node into the new tnode.
 | |
|  	 */
 | |
| +	while (n) {
 | |
| +		unsigned long index = get_index(key, n);
 | |
|  
 | |
| -	while (n && IS_TNODE(n)) {
 | |
| -		if (tkey_sub_equals(n->key, pos, n->pos-pos, key)) {
 | |
| -			tp = n;
 | |
| -			pos = n->pos + n->bits;
 | |
| -			n = tnode_get_child(n,
 | |
| -					    tkey_extract_bits(key,
 | |
| -							      n->pos,
 | |
| -							      n->bits));
 | |
| -
 | |
| -			BUG_ON(n && node_parent(n) != tp);
 | |
| -		} else
 | |
| +		/* This bit of code is a bit tricky but it combines multiple
 | |
| +		 * checks into a single check.  The prefix consists of the
 | |
| +		 * prefix plus zeros for the "bits" in the prefix. The index
 | |
| +		 * is the difference between the key and this value.  From
 | |
| +		 * this we can actually derive several pieces of data.
 | |
| +		 *   if !(index >> bits)
 | |
| +		 *     we know the value is child index
 | |
| +		 *   else
 | |
| +		 *     we have a mismatch in skip bits and failed
 | |
| +		 */
 | |
| +		if (index >> n->bits)
 | |
|  			break;
 | |
| -	}
 | |
| -
 | |
| -	/*
 | |
| -	 * n  ----> NULL, LEAF or TNODE
 | |
| -	 *
 | |
| -	 * tp is n's (parent) ----> NULL or TNODE
 | |
| -	 */
 | |
|  
 | |
| -	BUG_ON(tp && IS_LEAF(tp));
 | |
| -
 | |
| -	/* Case 1: n is a leaf. Compare prefixes */
 | |
| -
 | |
| -	if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
 | |
| -		li = leaf_info_new(plen);
 | |
| -
 | |
| -		if (!li)
 | |
| -			return NULL;
 | |
| +		/* we have found a leaf. Prefixes have already been compared */
 | |
| +		if (IS_LEAF(n)) {
 | |
| +			/* Case 1: n is a leaf, and prefixes match*/
 | |
| +			insert_leaf_info(&n->list, li);
 | |
| +			return fa_head;
 | |
| +		}
 | |
|  
 | |
| -		fa_head = &li->falh;
 | |
| -		insert_leaf_info(&n->list, li);
 | |
| -		goto done;
 | |
| +		tp = n;
 | |
| +		n = rcu_dereference_rtnl(n->child[index]);
 | |
|  	}
 | |
| -	l = leaf_new(key);
 | |
| -
 | |
| -	if (!l)
 | |
| -		return NULL;
 | |
|  
 | |
| -	li = leaf_info_new(plen);
 | |
| -
 | |
| -	if (!li) {
 | |
| -		node_free(l);
 | |
| +	l = leaf_new(key);
 | |
| +	if (!l) {
 | |
| +		free_leaf_info(li);
 | |
|  		return NULL;
 | |
|  	}
 | |
|  
 | |
| -	fa_head = &li->falh;
 | |
|  	insert_leaf_info(&l->list, li);
 | |
|  
 | |
| -	if (t->trie && n == NULL) {
 | |
| -		/* Case 2: n is NULL, and will just insert a new leaf */
 | |
| -
 | |
| -		node_set_parent(l, tp);
 | |
| -
 | |
| -		cindex = tkey_extract_bits(key, tp->pos, tp->bits);
 | |
| -		put_child(tp, cindex, l);
 | |
| -	} else {
 | |
| -		/* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
 | |
| -		/*
 | |
| -		 *  Add a new tnode here
 | |
| -		 *  first tnode need some special handling
 | |
| -		 */
 | |
| +	/* Case 2: n is a LEAF or a TNODE and the key doesn't match.
 | |
| +	 *
 | |
| +	 *  Add a new tnode here
 | |
| +	 *  first tnode need some special handling
 | |
| +	 *  leaves us in position for handling as case 3
 | |
| +	 */
 | |
| +	if (n) {
 | |
| +		struct tnode *tn;
 | |
| +		int newpos;
 | |
|  
 | |
| -		if (n) {
 | |
| -			pos = tp ? tp->pos+tp->bits : 0;
 | |
| -			newpos = tkey_mismatch(key, pos, n->key);
 | |
| -			tn = tnode_new(n->key, newpos, 1);
 | |
| -		} else {
 | |
| -			newpos = 0;
 | |
| -			tn = tnode_new(key, newpos, 1); /* First tnode */
 | |
| -		}
 | |
| +		newpos = KEYLENGTH - __fls(n->key ^ key) - 1;
 | |
|  
 | |
| +		tn = tnode_new(key, newpos, 1);
 | |
|  		if (!tn) {
 | |
|  			free_leaf_info(li);
 | |
|  			node_free(l);
 | |
|  			return NULL;
 | |
|  		}
 | |
|  
 | |
| -		node_set_parent(tn, tp);
 | |
| -
 | |
| -		missbit = tkey_extract_bits(key, newpos, 1);
 | |
| -		put_child(tn, missbit, l);
 | |
| -		put_child(tn, 1-missbit, n);
 | |
| -
 | |
| -		if (tp) {
 | |
| -			cindex = tkey_extract_bits(key, tp->pos, tp->bits);
 | |
| -			put_child(tp, cindex, tn);
 | |
| -		} else {
 | |
| -			rcu_assign_pointer(t->trie, tn);
 | |
| -		}
 | |
| +		/* initialize routes out of node */
 | |
| +		NODE_INIT_PARENT(tn, tp);
 | |
| +		put_child(tn, get_index(key, tn) ^ 1, n);
 | |
| +
 | |
| +		/* start adding routes into the node */
 | |
| +		put_child_root(tp, t, key, tn);
 | |
| +		node_set_parent(n, tn);
 | |
|  
 | |
| +		/* parent now has a NULL spot where the leaf can go */
 | |
|  		tp = tn;
 | |
|  	}
 | |
|  
 | |
| -	if (tp && tp->pos + tp->bits > 32)
 | |
| -		pr_warn("fib_trie tp=%p pos=%d, bits=%d, key=%0x plen=%d\n",
 | |
| -			tp, tp->pos, tp->bits, key, plen);
 | |
| -
 | |
| -	/* Rebalance the trie */
 | |
| +	/* Case 3: n is NULL, and will just insert a new leaf */
 | |
| +	if (tp) {
 | |
| +		NODE_INIT_PARENT(l, tp);
 | |
| +		put_child(tp, get_index(key, tp), l);
 | |
| +		trie_rebalance(t, tp);
 | |
| +	} else {
 | |
| +		rcu_assign_pointer(t->trie, l);
 | |
| +	}
 | |
|  
 | |
| -	trie_rebalance(t, tp);
 | |
| -done:
 | |
|  	return fa_head;
 | |
|  }
 | |
|  
 | |
| @@ -1470,11 +1416,11 @@ static void trie_leaf_remove(struct trie
 | |
|  	pr_debug("entering trie_leaf_remove(%p)\n", l);
 | |
|  
 | |
|  	if (tp) {
 | |
| -		t_key cindex = tkey_extract_bits(l->key, tp->pos, tp->bits);
 | |
| -		put_child(tp, cindex, NULL);
 | |
| +		put_child(tp, get_index(l->key, tp), NULL);
 | |
|  		trie_rebalance(t, tp);
 | |
| -	} else
 | |
| +	} else {
 | |
|  		RCU_INIT_POINTER(t->trie, NULL);
 | |
| +	}
 | |
|  
 | |
|  	node_free(l);
 | |
|  }
 |