diff options
author | Cong Wang <amwang@redhat.com> | 2013-01-17 03:34:11 -0500 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2013-01-17 04:03:57 -0500 |
commit | 7a9885b93bb623524468b37d04146d3422e099eb (patch) | |
tree | 11445bbd6fd8a3a1191dbf59d50c81f830f0cb7b | |
parent | 85168c0036fadf3657470b93cd9babeee8d123d7 (diff) |
xfrm: use separated locks to protect pointers of struct xfrm_state_afinfo
afinfo->type_map and afinfo->mode_map deserve separated locks,
they are different things.
We should just take RCU read lock to protect afinfo itself,
but not for the inner pointers.
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
-rw-r--r-- | net/xfrm/xfrm_state.c | 43 |
1 files changed, 18 insertions, 25 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 1522f19f273a..0adae918a7a2 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -168,57 +168,45 @@ int __xfrm_state_delete(struct xfrm_state *x); | |||
168 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); | 168 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); |
169 | void km_state_expired(struct xfrm_state *x, int hard, u32 portid); | 169 | void km_state_expired(struct xfrm_state *x, int hard, u32 portid); |
170 | 170 | ||
171 | static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family) | 171 | static DEFINE_SPINLOCK(xfrm_type_lock); |
172 | { | ||
173 | struct xfrm_state_afinfo *afinfo; | ||
174 | if (unlikely(family >= NPROTO)) | ||
175 | return NULL; | ||
176 | spin_lock_bh(&xfrm_state_afinfo_lock); | ||
177 | afinfo = xfrm_state_afinfo[family]; | ||
178 | if (unlikely(!afinfo)) | ||
179 | spin_unlock_bh(&xfrm_state_afinfo_lock); | ||
180 | return afinfo; | ||
181 | } | ||
182 | |||
183 | static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo) | ||
184 | { | ||
185 | spin_unlock_bh(&xfrm_state_afinfo_lock); | ||
186 | } | ||
187 | |||
188 | int xfrm_register_type(const struct xfrm_type *type, unsigned short family) | 172 | int xfrm_register_type(const struct xfrm_type *type, unsigned short family) |
189 | { | 173 | { |
190 | struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); | 174 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); |
191 | const struct xfrm_type **typemap; | 175 | const struct xfrm_type **typemap; |
192 | int err = 0; | 176 | int err = 0; |
193 | 177 | ||
194 | if (unlikely(afinfo == NULL)) | 178 | if (unlikely(afinfo == NULL)) |
195 | return -EAFNOSUPPORT; | 179 | return -EAFNOSUPPORT; |
196 | typemap = afinfo->type_map; | 180 | typemap = afinfo->type_map; |
181 | spin_lock_bh(&xfrm_type_lock); | ||
197 | 182 | ||
198 | if (likely(typemap[type->proto] == NULL)) | 183 | if (likely(typemap[type->proto] == NULL)) |
199 | typemap[type->proto] = type; | 184 | typemap[type->proto] = type; |
200 | else | 185 | else |
201 | err = -EEXIST; | 186 | err = -EEXIST; |
202 | xfrm_state_unlock_afinfo(afinfo); | 187 | spin_unlock_bh(&xfrm_type_lock); |
188 | xfrm_state_put_afinfo(afinfo); | ||
203 | return err; | 189 | return err; |
204 | } | 190 | } |
205 | EXPORT_SYMBOL(xfrm_register_type); | 191 | EXPORT_SYMBOL(xfrm_register_type); |
206 | 192 | ||
207 | int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family) | 193 | int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family) |
208 | { | 194 | { |
209 | struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); | 195 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); |
210 | const struct xfrm_type **typemap; | 196 | const struct xfrm_type **typemap; |
211 | int err = 0; | 197 | int err = 0; |
212 | 198 | ||
213 | if (unlikely(afinfo == NULL)) | 199 | if (unlikely(afinfo == NULL)) |
214 | return -EAFNOSUPPORT; | 200 | return -EAFNOSUPPORT; |
215 | typemap = afinfo->type_map; | 201 | typemap = afinfo->type_map; |
202 | spin_lock_bh(&xfrm_type_lock); | ||
216 | 203 | ||
217 | if (unlikely(typemap[type->proto] != type)) | 204 | if (unlikely(typemap[type->proto] != type)) |
218 | err = -ENOENT; | 205 | err = -ENOENT; |
219 | else | 206 | else |
220 | typemap[type->proto] = NULL; | 207 | typemap[type->proto] = NULL; |
221 | xfrm_state_unlock_afinfo(afinfo); | 208 | spin_unlock_bh(&xfrm_type_lock); |
209 | xfrm_state_put_afinfo(afinfo); | ||
222 | return err; | 210 | return err; |
223 | } | 211 | } |
224 | EXPORT_SYMBOL(xfrm_unregister_type); | 212 | EXPORT_SYMBOL(xfrm_unregister_type); |
@@ -255,6 +243,7 @@ static void xfrm_put_type(const struct xfrm_type *type) | |||
255 | module_put(type->owner); | 243 | module_put(type->owner); |
256 | } | 244 | } |
257 | 245 | ||
246 | static DEFINE_SPINLOCK(xfrm_mode_lock); | ||
258 | int xfrm_register_mode(struct xfrm_mode *mode, int family) | 247 | int xfrm_register_mode(struct xfrm_mode *mode, int family) |
259 | { | 248 | { |
260 | struct xfrm_state_afinfo *afinfo; | 249 | struct xfrm_state_afinfo *afinfo; |
@@ -264,12 +253,13 @@ int xfrm_register_mode(struct xfrm_mode *mode, int family) | |||
264 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | 253 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) |
265 | return -EINVAL; | 254 | return -EINVAL; |
266 | 255 | ||
267 | afinfo = xfrm_state_lock_afinfo(family); | 256 | afinfo = xfrm_state_get_afinfo(family); |
268 | if (unlikely(afinfo == NULL)) | 257 | if (unlikely(afinfo == NULL)) |
269 | return -EAFNOSUPPORT; | 258 | return -EAFNOSUPPORT; |
270 | 259 | ||
271 | err = -EEXIST; | 260 | err = -EEXIST; |
272 | modemap = afinfo->mode_map; | 261 | modemap = afinfo->mode_map; |
262 | spin_lock_bh(&xfrm_mode_lock); | ||
273 | if (modemap[mode->encap]) | 263 | if (modemap[mode->encap]) |
274 | goto out; | 264 | goto out; |
275 | 265 | ||
@@ -282,7 +272,8 @@ int xfrm_register_mode(struct xfrm_mode *mode, int family) | |||
282 | err = 0; | 272 | err = 0; |
283 | 273 | ||
284 | out: | 274 | out: |
285 | xfrm_state_unlock_afinfo(afinfo); | 275 | spin_unlock_bh(&xfrm_mode_lock); |
276 | xfrm_state_put_afinfo(afinfo); | ||
286 | return err; | 277 | return err; |
287 | } | 278 | } |
288 | EXPORT_SYMBOL(xfrm_register_mode); | 279 | EXPORT_SYMBOL(xfrm_register_mode); |
@@ -296,19 +287,21 @@ int xfrm_unregister_mode(struct xfrm_mode *mode, int family) | |||
296 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | 287 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) |
297 | return -EINVAL; | 288 | return -EINVAL; |
298 | 289 | ||
299 | afinfo = xfrm_state_lock_afinfo(family); | 290 | afinfo = xfrm_state_get_afinfo(family); |
300 | if (unlikely(afinfo == NULL)) | 291 | if (unlikely(afinfo == NULL)) |
301 | return -EAFNOSUPPORT; | 292 | return -EAFNOSUPPORT; |
302 | 293 | ||
303 | err = -ENOENT; | 294 | err = -ENOENT; |
304 | modemap = afinfo->mode_map; | 295 | modemap = afinfo->mode_map; |
296 | spin_lock_bh(&xfrm_mode_lock); | ||
305 | if (likely(modemap[mode->encap] == mode)) { | 297 | if (likely(modemap[mode->encap] == mode)) { |
306 | modemap[mode->encap] = NULL; | 298 | modemap[mode->encap] = NULL; |
307 | module_put(mode->afinfo->owner); | 299 | module_put(mode->afinfo->owner); |
308 | err = 0; | 300 | err = 0; |
309 | } | 301 | } |
310 | 302 | ||
311 | xfrm_state_unlock_afinfo(afinfo); | 303 | spin_unlock_bh(&xfrm_mode_lock); |
304 | xfrm_state_put_afinfo(afinfo); | ||
312 | return err; | 305 | return err; |
313 | } | 306 | } |
314 | EXPORT_SYMBOL(xfrm_unregister_mode); | 307 | EXPORT_SYMBOL(xfrm_unregister_mode); |