diff options
-rw-r--r-- | include/net/netfilter/nf_conntrack_helper.h | 4 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_helper.c | 58 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 9 |
3 files changed, 21 insertions, 50 deletions
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index 2f3af00643cf..4ca125e9b3ce 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h | |||
@@ -43,12 +43,8 @@ extern struct nf_conntrack_helper * | |||
43 | __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple); | 43 | __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple); |
44 | 44 | ||
45 | extern struct nf_conntrack_helper * | 45 | extern struct nf_conntrack_helper * |
46 | nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple); | ||
47 | |||
48 | extern struct nf_conntrack_helper * | ||
49 | __nf_conntrack_helper_find_byname(const char *name); | 46 | __nf_conntrack_helper_find_byname(const char *name); |
50 | 47 | ||
51 | extern void nf_ct_helper_put(struct nf_conntrack_helper *helper); | ||
52 | extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); | 48 | extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); |
53 | extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *); | 49 | extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *); |
54 | 50 | ||
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 96aa637c0932..42f781fcba64 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <net/netfilter/nf_conntrack_core.h> | 28 | #include <net/netfilter/nf_conntrack_core.h> |
29 | #include <net/netfilter/nf_conntrack_extend.h> | 29 | #include <net/netfilter/nf_conntrack_extend.h> |
30 | 30 | ||
31 | static DEFINE_MUTEX(nf_ct_helper_mutex); | ||
31 | static struct hlist_head *nf_ct_helper_hash __read_mostly; | 32 | static struct hlist_head *nf_ct_helper_hash __read_mostly; |
32 | static unsigned int nf_ct_helper_hsize __read_mostly; | 33 | static unsigned int nf_ct_helper_hsize __read_mostly; |
33 | static unsigned int nf_ct_helper_count __read_mostly; | 34 | static unsigned int nf_ct_helper_count __read_mostly; |
@@ -54,42 +55,13 @@ __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) | |||
54 | return NULL; | 55 | return NULL; |
55 | 56 | ||
56 | h = helper_hash(tuple); | 57 | h = helper_hash(tuple); |
57 | hlist_for_each_entry(helper, n, &nf_ct_helper_hash[h], hnode) { | 58 | hlist_for_each_entry_rcu(helper, n, &nf_ct_helper_hash[h], hnode) { |
58 | if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask)) | 59 | if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask)) |
59 | return helper; | 60 | return helper; |
60 | } | 61 | } |
61 | return NULL; | 62 | return NULL; |
62 | } | 63 | } |
63 | 64 | EXPORT_SYMBOL_GPL(__nf_ct_helper_find); | |
64 | struct nf_conntrack_helper * | ||
65 | nf_ct_helper_find_get(const struct nf_conntrack_tuple *tuple) | ||
66 | { | ||
67 | struct nf_conntrack_helper *helper; | ||
68 | |||
69 | /* need nf_conntrack_lock to assure that helper exists until | ||
70 | * try_module_get() is called */ | ||
71 | read_lock_bh(&nf_conntrack_lock); | ||
72 | |||
73 | helper = __nf_ct_helper_find(tuple); | ||
74 | if (helper) { | ||
75 | /* need to increase module usage count to assure helper will | ||
76 | * not go away while the caller is e.g. busy putting a | ||
77 | * conntrack in the hash that uses the helper */ | ||
78 | if (!try_module_get(helper->me)) | ||
79 | helper = NULL; | ||
80 | } | ||
81 | |||
82 | read_unlock_bh(&nf_conntrack_lock); | ||
83 | |||
84 | return helper; | ||
85 | } | ||
86 | EXPORT_SYMBOL_GPL(nf_ct_helper_find_get); | ||
87 | |||
88 | void nf_ct_helper_put(struct nf_conntrack_helper *helper) | ||
89 | { | ||
90 | module_put(helper->me); | ||
91 | } | ||
92 | EXPORT_SYMBOL_GPL(nf_ct_helper_put); | ||
93 | 65 | ||
94 | struct nf_conntrack_helper * | 66 | struct nf_conntrack_helper * |
95 | __nf_conntrack_helper_find_byname(const char *name) | 67 | __nf_conntrack_helper_find_byname(const char *name) |
@@ -99,7 +71,7 @@ __nf_conntrack_helper_find_byname(const char *name) | |||
99 | unsigned int i; | 71 | unsigned int i; |
100 | 72 | ||
101 | for (i = 0; i < nf_ct_helper_hsize; i++) { | 73 | for (i = 0; i < nf_ct_helper_hsize; i++) { |
102 | hlist_for_each_entry(h, n, &nf_ct_helper_hash[i], hnode) { | 74 | hlist_for_each_entry_rcu(h, n, &nf_ct_helper_hash[i], hnode) { |
103 | if (!strcmp(h->name, name)) | 75 | if (!strcmp(h->name, name)) |
104 | return h; | 76 | return h; |
105 | } | 77 | } |
@@ -140,10 +112,10 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | |||
140 | 112 | ||
141 | BUG_ON(me->timeout == 0); | 113 | BUG_ON(me->timeout == 0); |
142 | 114 | ||
143 | write_lock_bh(&nf_conntrack_lock); | 115 | mutex_lock(&nf_ct_helper_mutex); |
144 | hlist_add_head(&me->hnode, &nf_ct_helper_hash[h]); | 116 | hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]); |
145 | nf_ct_helper_count++; | 117 | nf_ct_helper_count++; |
146 | write_unlock_bh(&nf_conntrack_lock); | 118 | mutex_unlock(&nf_ct_helper_mutex); |
147 | 119 | ||
148 | return 0; | 120 | return 0; |
149 | } | 121 | } |
@@ -156,10 +128,17 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) | |||
156 | struct hlist_node *n, *next; | 128 | struct hlist_node *n, *next; |
157 | unsigned int i; | 129 | unsigned int i; |
158 | 130 | ||
159 | /* Need write lock here, to delete helper. */ | 131 | mutex_lock(&nf_ct_helper_mutex); |
160 | write_lock_bh(&nf_conntrack_lock); | 132 | hlist_del_rcu(&me->hnode); |
161 | hlist_del(&me->hnode); | ||
162 | nf_ct_helper_count--; | 133 | nf_ct_helper_count--; |
134 | mutex_unlock(&nf_ct_helper_mutex); | ||
135 | |||
136 | /* Make sure every nothing is still using the helper unless its a | ||
137 | * connection in the hash. | ||
138 | */ | ||
139 | synchronize_rcu(); | ||
140 | |||
141 | write_lock_bh(&nf_conntrack_lock); | ||
163 | 142 | ||
164 | /* Get rid of expectations */ | 143 | /* Get rid of expectations */ |
165 | for (i = 0; i < nf_ct_expect_hsize; i++) { | 144 | for (i = 0; i < nf_ct_expect_hsize; i++) { |
@@ -182,9 +161,6 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) | |||
182 | unhelp(h, me); | 161 | unhelp(h, me); |
183 | } | 162 | } |
184 | write_unlock_bh(&nf_conntrack_lock); | 163 | write_unlock_bh(&nf_conntrack_lock); |
185 | |||
186 | /* Someone could be still looking at the helper in a bh. */ | ||
187 | synchronize_net(); | ||
188 | } | 164 | } |
189 | EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister); | 165 | EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister); |
190 | 166 | ||
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index bdae2924d425..b6c0935e09df 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -1167,11 +1167,12 @@ ctnetlink_create_conntrack(struct nlattr *cda[], | |||
1167 | ct->mark = ntohl(nla_get_be32(cda[CTA_MARK])); | 1167 | ct->mark = ntohl(nla_get_be32(cda[CTA_MARK])); |
1168 | #endif | 1168 | #endif |
1169 | 1169 | ||
1170 | helper = nf_ct_helper_find_get(rtuple); | 1170 | rcu_read_lock(); |
1171 | helper = __nf_ct_helper_find(rtuple); | ||
1171 | if (helper) { | 1172 | if (helper) { |
1172 | help = nf_ct_helper_ext_add(ct, GFP_KERNEL); | 1173 | help = nf_ct_helper_ext_add(ct, GFP_KERNEL); |
1173 | if (help == NULL) { | 1174 | if (help == NULL) { |
1174 | nf_ct_helper_put(helper); | 1175 | rcu_read_unlock(); |
1175 | err = -ENOMEM; | 1176 | err = -ENOMEM; |
1176 | goto err; | 1177 | goto err; |
1177 | } | 1178 | } |
@@ -1187,9 +1188,7 @@ ctnetlink_create_conntrack(struct nlattr *cda[], | |||
1187 | 1188 | ||
1188 | add_timer(&ct->timeout); | 1189 | add_timer(&ct->timeout); |
1189 | nf_conntrack_hash_insert(ct); | 1190 | nf_conntrack_hash_insert(ct); |
1190 | 1191 | rcu_read_unlock(); | |
1191 | if (helper) | ||
1192 | nf_ct_helper_put(helper); | ||
1193 | 1192 | ||
1194 | return 0; | 1193 | return 0; |
1195 | 1194 | ||