diff options
| author | Eric W. Biederman <ebiederm@xmission.com> | 2009-12-02 21:29:05 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-12-03 15:22:03 -0500 |
| commit | d79d792ef9f99cca463b6619a93e860d1c833a6e (patch) | |
| tree | 06d8a085701546be48ac104fd4f2413a6371180c | |
| parent | 04dc7f6be3a7b308f8545bb45772c9fb75f71aca (diff) | |
net: Allow xfrm_user_net_exit to batch efficiently.
xfrm.nlsk is provided by the xfrm_user module and is access via rcu from
other parts of the xfrm code. Add xfrm.nlsk_stash a copy of xfrm.nlsk that
will never be set to NULL. This allows the synchronize_net and
netlink_kernel_release to be deferred until a whole batch of xfrm.nlsk sockets
have been set to NULL.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/netns/xfrm.h | 1 | ||||
| -rw-r--r-- | net/xfrm/xfrm_user.c | 18 |
2 files changed, 11 insertions, 8 deletions
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h index 1ba912749caa..56f8e5585df7 100644 --- a/include/net/netns/xfrm.h +++ b/include/net/netns/xfrm.h | |||
| @@ -43,6 +43,7 @@ struct netns_xfrm { | |||
| 43 | struct work_struct policy_hash_work; | 43 | struct work_struct policy_hash_work; |
| 44 | 44 | ||
| 45 | struct sock *nlsk; | 45 | struct sock *nlsk; |
| 46 | struct sock *nlsk_stash; | ||
| 46 | 47 | ||
| 47 | u32 sysctl_aevent_etime; | 48 | u32 sysctl_aevent_etime; |
| 48 | u32 sysctl_aevent_rseqth; | 49 | u32 sysctl_aevent_rseqth; |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index fb42d778d278..1ada6186933c 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
| @@ -2721,22 +2721,24 @@ static int __net_init xfrm_user_net_init(struct net *net) | |||
| 2721 | xfrm_netlink_rcv, NULL, THIS_MODULE); | 2721 | xfrm_netlink_rcv, NULL, THIS_MODULE); |
| 2722 | if (nlsk == NULL) | 2722 | if (nlsk == NULL) |
| 2723 | return -ENOMEM; | 2723 | return -ENOMEM; |
| 2724 | net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */ | ||
| 2724 | rcu_assign_pointer(net->xfrm.nlsk, nlsk); | 2725 | rcu_assign_pointer(net->xfrm.nlsk, nlsk); |
| 2725 | return 0; | 2726 | return 0; |
| 2726 | } | 2727 | } |
| 2727 | 2728 | ||
| 2728 | static void __net_exit xfrm_user_net_exit(struct net *net) | 2729 | static void __net_exit xfrm_user_net_exit(struct list_head *net_exit_list) |
| 2729 | { | 2730 | { |
| 2730 | struct sock *nlsk = net->xfrm.nlsk; | 2731 | struct net *net; |
| 2731 | 2732 | list_for_each_entry(net, net_exit_list, exit_list) | |
| 2732 | rcu_assign_pointer(net->xfrm.nlsk, NULL); | 2733 | rcu_assign_pointer(net->xfrm.nlsk, NULL); |
| 2733 | synchronize_rcu(); | 2734 | synchronize_net(); |
| 2734 | netlink_kernel_release(nlsk); | 2735 | list_for_each_entry(net, net_exit_list, exit_list) |
| 2736 | netlink_kernel_release(net->xfrm.nlsk_stash); | ||
| 2735 | } | 2737 | } |
| 2736 | 2738 | ||
| 2737 | static struct pernet_operations xfrm_user_net_ops = { | 2739 | static struct pernet_operations xfrm_user_net_ops = { |
| 2738 | .init = xfrm_user_net_init, | 2740 | .init = xfrm_user_net_init, |
| 2739 | .exit = xfrm_user_net_exit, | 2741 | .exit_batch = xfrm_user_net_exit, |
| 2740 | }; | 2742 | }; |
| 2741 | 2743 | ||
| 2742 | static int __init xfrm_user_init(void) | 2744 | static int __init xfrm_user_init(void) |
