diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-10-14 16:53:34 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-10-17 16:53:15 -0400 |
commit | 117a8cdea3647e8e11fac10d14eafefc20f9bda5 (patch) | |
tree | b030a78c033998bdc725935b4123695bfb8c24e9 /net/ipv4 | |
parent | 9bef83edfba72ba58b42c14fb046da2199574bc0 (diff) |
fib_hash: RCU conversion phase 1
First step for RCU conversion of fib_hash :
struct fn_zone are created and never deleted.
Very classic conversion, using rcu_assign_pointer(), rcu_dereference()
and rtnl_dereference() verbs.
__rcu markers on fz_next and fn_zone_list
They are created under RTNL, we dont need fib_hash_lock anymore in
fn_new_zone().
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/fib_hash.c | 57 |
1 files changed, 38 insertions, 19 deletions
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 10001aa40692..04f05a96b75b 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c | |||
@@ -57,7 +57,7 @@ struct fib_node { | |||
57 | #define EMBEDDED_HASH_SIZE (L1_CACHE_BYTES / sizeof(struct hlist_head)) | 57 | #define EMBEDDED_HASH_SIZE (L1_CACHE_BYTES / sizeof(struct hlist_head)) |
58 | 58 | ||
59 | struct fn_zone { | 59 | struct fn_zone { |
60 | struct fn_zone *fz_next; /* Next not empty zone */ | 60 | struct fn_zone __rcu *fz_next; /* Next not empty zone */ |
61 | struct hlist_head *fz_hash; /* Hash table pointer */ | 61 | struct hlist_head *fz_hash; /* Hash table pointer */ |
62 | u32 fz_hashmask; /* (fz_divisor - 1) */ | 62 | u32 fz_hashmask; /* (fz_divisor - 1) */ |
63 | 63 | ||
@@ -73,8 +73,8 @@ struct fn_zone { | |||
73 | }; | 73 | }; |
74 | 74 | ||
75 | struct fn_hash { | 75 | struct fn_hash { |
76 | struct fn_zone *fn_zones[33]; | 76 | struct fn_zone *fn_zones[33]; |
77 | struct fn_zone *fn_zone_list; | 77 | struct fn_zone __rcu *fn_zone_list; |
78 | }; | 78 | }; |
79 | 79 | ||
80 | static inline u32 fn_hash(__be32 key, struct fn_zone *fz) | 80 | static inline u32 fn_hash(__be32 key, struct fn_zone *fz) |
@@ -219,21 +219,21 @@ fn_new_zone(struct fn_hash *table, int z) | |||
219 | fz->fz_mask = inet_make_mask(z); | 219 | fz->fz_mask = inet_make_mask(z); |
220 | 220 | ||
221 | /* Find the first not empty zone with more specific mask */ | 221 | /* Find the first not empty zone with more specific mask */ |
222 | for (i=z+1; i<=32; i++) | 222 | for (i = z + 1; i <= 32; i++) |
223 | if (table->fn_zones[i]) | 223 | if (table->fn_zones[i]) |
224 | break; | 224 | break; |
225 | write_lock_bh(&fib_hash_lock); | 225 | if (i > 32) { |
226 | if (i>32) { | ||
227 | /* No more specific masks, we are the first. */ | 226 | /* No more specific masks, we are the first. */ |
228 | fz->fz_next = table->fn_zone_list; | 227 | rcu_assign_pointer(fz->fz_next, |
229 | table->fn_zone_list = fz; | 228 | rtnl_dereference(table->fn_zone_list)); |
229 | rcu_assign_pointer(table->fn_zone_list, fz); | ||
230 | } else { | 230 | } else { |
231 | fz->fz_next = table->fn_zones[i]->fz_next; | 231 | rcu_assign_pointer(fz->fz_next, |
232 | table->fn_zones[i]->fz_next = fz; | 232 | rtnl_dereference(table->fn_zones[i]->fz_next)); |
233 | rcu_assign_pointer(table->fn_zones[i]->fz_next, fz); | ||
233 | } | 234 | } |
234 | table->fn_zones[z] = fz; | 235 | table->fn_zones[z] = fz; |
235 | fib_hash_genid++; | 236 | fib_hash_genid++; |
236 | write_unlock_bh(&fib_hash_lock); | ||
237 | return fz; | 237 | return fz; |
238 | } | 238 | } |
239 | 239 | ||
@@ -245,8 +245,11 @@ int fib_table_lookup(struct fib_table *tb, | |||
245 | struct fn_zone *fz; | 245 | struct fn_zone *fz; |
246 | struct fn_hash *t = (struct fn_hash *)tb->tb_data; | 246 | struct fn_hash *t = (struct fn_hash *)tb->tb_data; |
247 | 247 | ||
248 | rcu_read_lock(); | ||
248 | read_lock(&fib_hash_lock); | 249 | read_lock(&fib_hash_lock); |
249 | for (fz = t->fn_zone_list; fz; fz = fz->fz_next) { | 250 | for (fz = rcu_dereference(t->fn_zone_list); |
251 | fz != NULL; | ||
252 | fz = rcu_dereference(fz->fz_next)) { | ||
250 | struct hlist_head *head; | 253 | struct hlist_head *head; |
251 | struct hlist_node *node; | 254 | struct hlist_node *node; |
252 | struct fib_node *f; | 255 | struct fib_node *f; |
@@ -267,6 +270,7 @@ int fib_table_lookup(struct fib_table *tb, | |||
267 | err = 1; | 270 | err = 1; |
268 | out: | 271 | out: |
269 | read_unlock(&fib_hash_lock); | 272 | read_unlock(&fib_hash_lock); |
273 | rcu_read_unlock(); | ||
270 | return err; | 274 | return err; |
271 | } | 275 | } |
272 | 276 | ||
@@ -362,6 +366,7 @@ static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key) | |||
362 | return NULL; | 366 | return NULL; |
363 | } | 367 | } |
364 | 368 | ||
369 | /* Caller must hold RTNL. */ | ||
365 | int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) | 370 | int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) |
366 | { | 371 | { |
367 | struct fn_hash *table = (struct fn_hash *) tb->tb_data; | 372 | struct fn_hash *table = (struct fn_hash *) tb->tb_data; |
@@ -657,13 +662,16 @@ static int fn_flush_list(struct fn_zone *fz, int idx) | |||
657 | return found; | 662 | return found; |
658 | } | 663 | } |
659 | 664 | ||
665 | /* caller must hold RTNL. */ | ||
660 | int fib_table_flush(struct fib_table *tb) | 666 | int fib_table_flush(struct fib_table *tb) |
661 | { | 667 | { |
662 | struct fn_hash *table = (struct fn_hash *) tb->tb_data; | 668 | struct fn_hash *table = (struct fn_hash *) tb->tb_data; |
663 | struct fn_zone *fz; | 669 | struct fn_zone *fz; |
664 | int found = 0; | 670 | int found = 0; |
665 | 671 | ||
666 | for (fz = table->fn_zone_list; fz; fz = fz->fz_next) { | 672 | for (fz = rtnl_dereference(table->fn_zone_list); |
673 | fz != NULL; | ||
674 | fz = rtnl_dereference(fz->fz_next)) { | ||
667 | int i; | 675 | int i; |
668 | 676 | ||
669 | for (i = fz->fz_divisor - 1; i >= 0; i--) | 677 | for (i = fz->fz_divisor - 1; i >= 0; i--) |
@@ -741,23 +749,29 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb, | |||
741 | int fib_table_dump(struct fib_table *tb, struct sk_buff *skb, | 749 | int fib_table_dump(struct fib_table *tb, struct sk_buff *skb, |
742 | struct netlink_callback *cb) | 750 | struct netlink_callback *cb) |
743 | { | 751 | { |
744 | int m, s_m; | 752 | int m = 0, s_m; |
745 | struct fn_zone *fz; | 753 | struct fn_zone *fz; |
746 | struct fn_hash *table = (struct fn_hash *)tb->tb_data; | 754 | struct fn_hash *table = (struct fn_hash *)tb->tb_data; |
747 | 755 | ||
748 | s_m = cb->args[2]; | 756 | s_m = cb->args[2]; |
757 | rcu_read_lock(); | ||
749 | read_lock(&fib_hash_lock); | 758 | read_lock(&fib_hash_lock); |
750 | for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) { | 759 | for (fz = rcu_dereference(table->fn_zone_list); |
751 | if (m < s_m) continue; | 760 | fz != NULL; |
761 | fz = rcu_dereference(fz->fz_next), m++) { | ||
762 | if (m < s_m) | ||
763 | continue; | ||
752 | if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) { | 764 | if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) { |
753 | cb->args[2] = m; | 765 | cb->args[2] = m; |
754 | read_unlock(&fib_hash_lock); | 766 | read_unlock(&fib_hash_lock); |
767 | rcu_read_unlock(); | ||
755 | return -1; | 768 | return -1; |
756 | } | 769 | } |
757 | memset(&cb->args[3], 0, | 770 | memset(&cb->args[3], 0, |
758 | sizeof(cb->args) - 3*sizeof(cb->args[0])); | 771 | sizeof(cb->args) - 3*sizeof(cb->args[0])); |
759 | } | 772 | } |
760 | read_unlock(&fib_hash_lock); | 773 | read_unlock(&fib_hash_lock); |
774 | rcu_read_unlock(); | ||
761 | cb->args[2] = m; | 775 | cb->args[2] = m; |
762 | return skb->len; | 776 | return skb->len; |
763 | } | 777 | } |
@@ -820,8 +834,9 @@ static struct fib_alias *fib_get_first(struct seq_file *seq) | |||
820 | iter->genid = fib_hash_genid; | 834 | iter->genid = fib_hash_genid; |
821 | iter->valid = 1; | 835 | iter->valid = 1; |
822 | 836 | ||
823 | for (iter->zone = table->fn_zone_list; iter->zone; | 837 | for (iter->zone = rcu_dereference(table->fn_zone_list); |
824 | iter->zone = iter->zone->fz_next) { | 838 | iter->zone != NULL; |
839 | iter->zone = rcu_dereference(iter->zone->fz_next)) { | ||
825 | int maxslot; | 840 | int maxslot; |
826 | 841 | ||
827 | if (!iter->zone->fz_nent) | 842 | if (!iter->zone->fz_nent) |
@@ -906,7 +921,7 @@ static struct fib_alias *fib_get_next(struct seq_file *seq) | |||
906 | } | 921 | } |
907 | } | 922 | } |
908 | 923 | ||
909 | iter->zone = iter->zone->fz_next; | 924 | iter->zone = rcu_dereference(iter->zone->fz_next); |
910 | 925 | ||
911 | if (!iter->zone) | 926 | if (!iter->zone) |
912 | goto out; | 927 | goto out; |
@@ -946,9 +961,11 @@ static struct fib_alias *fib_get_idx(struct seq_file *seq, loff_t pos) | |||
946 | 961 | ||
947 | static void *fib_seq_start(struct seq_file *seq, loff_t *pos) | 962 | static void *fib_seq_start(struct seq_file *seq, loff_t *pos) |
948 | __acquires(fib_hash_lock) | 963 | __acquires(fib_hash_lock) |
964 | __acquires(RCU) | ||
949 | { | 965 | { |
950 | void *v = NULL; | 966 | void *v = NULL; |
951 | 967 | ||
968 | rcu_read_lock(); | ||
952 | read_lock(&fib_hash_lock); | 969 | read_lock(&fib_hash_lock); |
953 | if (fib_get_table(seq_file_net(seq), RT_TABLE_MAIN)) | 970 | if (fib_get_table(seq_file_net(seq), RT_TABLE_MAIN)) |
954 | v = *pos ? fib_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; | 971 | v = *pos ? fib_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; |
@@ -963,8 +980,10 @@ static void *fib_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
963 | 980 | ||
964 | static void fib_seq_stop(struct seq_file *seq, void *v) | 981 | static void fib_seq_stop(struct seq_file *seq, void *v) |
965 | __releases(fib_hash_lock) | 982 | __releases(fib_hash_lock) |
983 | __releases(RCU) | ||
966 | { | 984 | { |
967 | read_unlock(&fib_hash_lock); | 985 | read_unlock(&fib_hash_lock); |
986 | rcu_read_unlock(); | ||
968 | } | 987 | } |
969 | 988 | ||
970 | static unsigned fib_flag_trans(int type, __be32 mask, struct fib_info *fi) | 989 | static unsigned fib_flag_trans(int type, __be32 mask, struct fib_info *fi) |