1
0

080-15-fib_trie-Push-tnode-flushing-down-to-inflate-halve.patch 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. From: Alexander Duyck <alexander.h.duyck@redhat.com>
  2. Date: Wed, 31 Dec 2014 10:56:49 -0800
  3. Subject: [PATCH] fib_trie: Push tnode flushing down to inflate/halve
  4. This change pushes the tnode freeing down into the inflate and halve
  5. functions. It makes more sense here as we have a better grasp of what is
  6. going on and when a given cluster of nodes is ready to be freed.
  7. I believe this may address a bug in the freeing logic as well. For some
  8. reason if the freelist got to a certain size we would call
  9. synchronize_rcu(). I'm assuming that what they meant to do is call
  10. synchronize_rcu() after they had handed off that much memory via
  11. call_rcu(). As such that is what I have updated the behavior to be.
  12. Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
  13. Signed-off-by: David S. Miller <davem@davemloft.net>
  14. ---
  15. --- a/net/ipv4/fib_trie.c
  16. +++ b/net/ipv4/fib_trie.c
  17. @@ -147,8 +147,6 @@ struct trie {
  18. };
  19. static void resize(struct trie *t, struct tnode *tn);
  20. -/* tnodes to free after resize(); protected by RTNL */
  21. -static struct callback_head *tnode_free_head;
  22. static size_t tnode_free_size;
  23. /*
  24. @@ -307,32 +305,6 @@ static struct tnode *tnode_alloc(size_t
  25. return vzalloc(size);
  26. }
  27. -static void tnode_free_safe(struct tnode *tn)
  28. -{
  29. - BUG_ON(IS_LEAF(tn));
  30. - tn->rcu.next = tnode_free_head;
  31. - tnode_free_head = &tn->rcu;
  32. -}
  33. -
  34. -static void tnode_free_flush(void)
  35. -{
  36. - struct callback_head *head;
  37. -
  38. - while ((head = tnode_free_head)) {
  39. - struct tnode *tn = container_of(head, struct tnode, rcu);
  40. -
  41. - tnode_free_head = head->next;
  42. - tnode_free_size += offsetof(struct tnode, child[1 << tn->bits]);
  43. -
  44. - node_free(tn);
  45. - }
  46. -
  47. - if (tnode_free_size >= PAGE_SIZE * sync_pages) {
  48. - tnode_free_size = 0;
  49. - synchronize_rcu();
  50. - }
  51. -}
  52. -
  53. static struct tnode *leaf_new(t_key key)
  54. {
  55. struct tnode *l = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL);
  56. @@ -433,17 +405,33 @@ static void put_child_root(struct tnode
  57. rcu_assign_pointer(t->trie, n);
  58. }
  59. -static void tnode_clean_free(struct tnode *tn)
  60. +static inline void tnode_free_init(struct tnode *tn)
  61. {
  62. - struct tnode *tofree;
  63. - unsigned long i;
  64. + tn->rcu.next = NULL;
  65. +}
  66. +
  67. +static inline void tnode_free_append(struct tnode *tn, struct tnode *n)
  68. +{
  69. + n->rcu.next = tn->rcu.next;
  70. + tn->rcu.next = &n->rcu;
  71. +}
  72. - for (i = 0; i < tnode_child_length(tn); i++) {
  73. - tofree = tnode_get_child(tn, i);
  74. - if (tofree)
  75. - node_free(tofree);
  76. +static void tnode_free(struct tnode *tn)
  77. +{
  78. + struct callback_head *head = &tn->rcu;
  79. +
  80. + while (head) {
  81. + head = head->next;
  82. + tnode_free_size += offsetof(struct tnode, child[1 << tn->bits]);
  83. + node_free(tn);
  84. +
  85. + tn = container_of(head, struct tnode, rcu);
  86. + }
  87. +
  88. + if (tnode_free_size >= PAGE_SIZE * sync_pages) {
  89. + tnode_free_size = 0;
  90. + synchronize_rcu();
  91. }
  92. - node_free(tn);
  93. }
  94. static int inflate(struct trie *t, struct tnode *oldtnode)
  95. @@ -476,20 +464,23 @@ static int inflate(struct trie *t, struc
  96. inode->bits - 1);
  97. if (!left)
  98. goto nomem;
  99. + tnode_free_append(tn, left);
  100. right = tnode_new(inode->key | m, inode->pos,
  101. inode->bits - 1);
  102. - if (!right) {
  103. - node_free(left);
  104. + if (!right)
  105. goto nomem;
  106. - }
  107. + tnode_free_append(tn, right);
  108. put_child(tn, 2*i, left);
  109. put_child(tn, 2*i+1, right);
  110. }
  111. }
  112. + /* prepare oldtnode to be freed */
  113. + tnode_free_init(oldtnode);
  114. +
  115. for (i = 0; i < olen; i++) {
  116. struct tnode *inode = tnode_get_child(oldtnode, i);
  117. struct tnode *left, *right;
  118. @@ -505,12 +496,13 @@ static int inflate(struct trie *t, struc
  119. continue;
  120. }
  121. + /* drop the node in the old tnode free list */
  122. + tnode_free_append(oldtnode, inode);
  123. +
  124. /* An internal node with two children */
  125. if (inode->bits == 1) {
  126. put_child(tn, 2*i, rtnl_dereference(inode->child[0]));
  127. put_child(tn, 2*i+1, rtnl_dereference(inode->child[1]));
  128. -
  129. - tnode_free_safe(inode);
  130. continue;
  131. }
  132. @@ -556,17 +548,19 @@ static int inflate(struct trie *t, struc
  133. put_child(tn, 2 * i, left);
  134. put_child(tn, 2 * i + 1, right);
  135. - tnode_free_safe(inode);
  136. -
  137. + /* resize child nodes */
  138. resize(t, left);
  139. resize(t, right);
  140. }
  141. put_child_root(tp, t, tn->key, tn);
  142. - tnode_free_safe(oldtnode);
  143. +
  144. + /* we completed without error, prepare to free old node */
  145. + tnode_free(oldtnode);
  146. return 0;
  147. nomem:
  148. - tnode_clean_free(tn);
  149. + /* all pointers should be clean so we are done */
  150. + tnode_free(tn);
  151. return -ENOMEM;
  152. }
  153. @@ -599,17 +593,20 @@ static int halve(struct trie *t, struct
  154. struct tnode *newn;
  155. newn = tnode_new(left->key, oldtnode->pos, 1);
  156. -
  157. if (!newn) {
  158. - tnode_clean_free(tn);
  159. + tnode_free(tn);
  160. return -ENOMEM;
  161. }
  162. + tnode_free_append(tn, newn);
  163. put_child(tn, i/2, newn);
  164. }
  165. }
  166. + /* prepare oldtnode to be freed */
  167. + tnode_free_init(oldtnode);
  168. +
  169. for (i = 0; i < olen; i += 2) {
  170. struct tnode *newBinNode;
  171. @@ -636,11 +633,14 @@ static int halve(struct trie *t, struct
  172. put_child(tn, i / 2, newBinNode);
  173. + /* resize child node */
  174. resize(t, newBinNode);
  175. }
  176. put_child_root(tp, t, tn->key, tn);
  177. - tnode_free_safe(oldtnode);
  178. +
  179. + /* all pointers should be clean so we are done */
  180. + tnode_free(oldtnode);
  181. return 0;
  182. }
  183. @@ -798,7 +798,8 @@ no_children:
  184. node_set_parent(n, tp);
  185. /* drop dead node */
  186. - tnode_free_safe(tn);
  187. + tnode_free_init(tn);
  188. + tnode_free(tn);
  189. }
  190. }
  191. @@ -884,16 +885,12 @@ static void trie_rebalance(struct trie *
  192. while ((tp = node_parent(tn)) != NULL) {
  193. resize(t, tn);
  194. -
  195. - tnode_free_flush();
  196. tn = tp;
  197. }
  198. /* Handle last (top) tnode */
  199. if (IS_TNODE(tn))
  200. resize(t, tn);
  201. -
  202. - tnode_free_flush();
  203. }
  204. /* only used from updater-side */