aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/xfrm/xfrm_policy.c39
1 files changed, 21 insertions, 18 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index c5a5165a5927..5ad4d2c4b83c 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -42,13 +42,14 @@ static DEFINE_SPINLOCK(xfrm_policy_sk_bundle_lock);
42static struct dst_entry *xfrm_policy_sk_bundles; 42static struct dst_entry *xfrm_policy_sk_bundles;
43static DEFINE_RWLOCK(xfrm_policy_lock); 43static DEFINE_RWLOCK(xfrm_policy_lock);
44 44
45static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); 45static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
46static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; 46static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO]
47 __read_mostly;
47 48
48static struct kmem_cache *xfrm_dst_cache __read_mostly; 49static struct kmem_cache *xfrm_dst_cache __read_mostly;
49 50
50static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); 51static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
51static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); 52static inline void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
52static void xfrm_init_pmtu(struct dst_entry *dst); 53static void xfrm_init_pmtu(struct dst_entry *dst);
53static int stale_bundle(struct dst_entry *dst); 54static int stale_bundle(struct dst_entry *dst);
54static int xfrm_bundle_ok(struct xfrm_dst *xdst); 55static int xfrm_bundle_ok(struct xfrm_dst *xdst);
@@ -2418,7 +2419,7 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
2418 return -EINVAL; 2419 return -EINVAL;
2419 if (unlikely(afinfo->family >= NPROTO)) 2420 if (unlikely(afinfo->family >= NPROTO))
2420 return -EAFNOSUPPORT; 2421 return -EAFNOSUPPORT;
2421 write_lock_bh(&xfrm_policy_afinfo_lock); 2422 spin_lock_bh(&xfrm_policy_afinfo_lock);
2422 if (unlikely(xfrm_policy_afinfo[afinfo->family] != NULL)) 2423 if (unlikely(xfrm_policy_afinfo[afinfo->family] != NULL))
2423 err = -ENOBUFS; 2424 err = -ENOBUFS;
2424 else { 2425 else {
@@ -2439,9 +2440,9 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
2439 dst_ops->neigh_lookup = xfrm_neigh_lookup; 2440 dst_ops->neigh_lookup = xfrm_neigh_lookup;
2440 if (likely(afinfo->garbage_collect == NULL)) 2441 if (likely(afinfo->garbage_collect == NULL))
2441 afinfo->garbage_collect = xfrm_garbage_collect_deferred; 2442 afinfo->garbage_collect = xfrm_garbage_collect_deferred;
2442 xfrm_policy_afinfo[afinfo->family] = afinfo; 2443 rcu_assign_pointer(xfrm_policy_afinfo[afinfo->family], afinfo);
2443 } 2444 }
2444 write_unlock_bh(&xfrm_policy_afinfo_lock); 2445 spin_unlock_bh(&xfrm_policy_afinfo_lock);
2445 2446
2446 rtnl_lock(); 2447 rtnl_lock();
2447 for_each_net(net) { 2448 for_each_net(net) {
@@ -2474,13 +2475,14 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
2474 return -EINVAL; 2475 return -EINVAL;
2475 if (unlikely(afinfo->family >= NPROTO)) 2476 if (unlikely(afinfo->family >= NPROTO))
2476 return -EAFNOSUPPORT; 2477 return -EAFNOSUPPORT;
2477 write_lock_bh(&xfrm_policy_afinfo_lock); 2478 spin_lock_bh(&xfrm_policy_afinfo_lock);
2478 if (likely(xfrm_policy_afinfo[afinfo->family] != NULL)) { 2479 if (likely(xfrm_policy_afinfo[afinfo->family] != NULL)) {
2479 if (unlikely(xfrm_policy_afinfo[afinfo->family] != afinfo)) 2480 if (unlikely(xfrm_policy_afinfo[afinfo->family] != afinfo))
2480 err = -EINVAL; 2481 err = -EINVAL;
2481 else { 2482 else {
2482 struct dst_ops *dst_ops = afinfo->dst_ops; 2483 struct dst_ops *dst_ops = afinfo->dst_ops;
2483 xfrm_policy_afinfo[afinfo->family] = NULL; 2484 rcu_assign_pointer(xfrm_policy_afinfo[afinfo->family],
2485 NULL);
2484 dst_ops->kmem_cachep = NULL; 2486 dst_ops->kmem_cachep = NULL;
2485 dst_ops->check = NULL; 2487 dst_ops->check = NULL;
2486 dst_ops->negative_advice = NULL; 2488 dst_ops->negative_advice = NULL;
@@ -2488,7 +2490,8 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
2488 afinfo->garbage_collect = NULL; 2490 afinfo->garbage_collect = NULL;
2489 } 2491 }
2490 } 2492 }
2491 write_unlock_bh(&xfrm_policy_afinfo_lock); 2493 spin_unlock_bh(&xfrm_policy_afinfo_lock);
2494 synchronize_rcu();
2492 return err; 2495 return err;
2493} 2496}
2494EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); 2497EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
@@ -2497,16 +2500,16 @@ static void __net_init xfrm_dst_ops_init(struct net *net)
2497{ 2500{
2498 struct xfrm_policy_afinfo *afinfo; 2501 struct xfrm_policy_afinfo *afinfo;
2499 2502
2500 read_lock_bh(&xfrm_policy_afinfo_lock); 2503 rcu_read_lock_bh();
2501 afinfo = xfrm_policy_afinfo[AF_INET]; 2504 afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET]);
2502 if (afinfo) 2505 if (afinfo)
2503 net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops; 2506 net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops;
2504#if IS_ENABLED(CONFIG_IPV6) 2507#if IS_ENABLED(CONFIG_IPV6)
2505 afinfo = xfrm_policy_afinfo[AF_INET6]; 2508 afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET6]);
2506 if (afinfo) 2509 if (afinfo)
2507 net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops; 2510 net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops;
2508#endif 2511#endif
2509 read_unlock_bh(&xfrm_policy_afinfo_lock); 2512 rcu_read_unlock_bh();
2510} 2513}
2511 2514
2512static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) 2515static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
@@ -2514,16 +2517,16 @@ static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
2514 struct xfrm_policy_afinfo *afinfo; 2517 struct xfrm_policy_afinfo *afinfo;
2515 if (unlikely(family >= NPROTO)) 2518 if (unlikely(family >= NPROTO))
2516 return NULL; 2519 return NULL;
2517 read_lock(&xfrm_policy_afinfo_lock); 2520 rcu_read_lock();
2518 afinfo = xfrm_policy_afinfo[family]; 2521 afinfo = rcu_dereference(xfrm_policy_afinfo[family]);
2519 if (unlikely(!afinfo)) 2522 if (unlikely(!afinfo))
2520 read_unlock(&xfrm_policy_afinfo_lock); 2523 rcu_read_unlock();
2521 return afinfo; 2524 return afinfo;
2522} 2525}
2523 2526
2524static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo) 2527static inline void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
2525{ 2528{
2526 read_unlock(&xfrm_policy_afinfo_lock); 2529 rcu_read_unlock();
2527} 2530}
2528 2531
2529static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr) 2532static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)