diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2016-11-28 23:58:04 -0800 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-11-28 23:58:04 -0800 |
commit | 2be8fc81c3adef891480d3abd19639860d838443 (patch) | |
tree | 91f4720b3d455de6104a0bfca5f112d29fcacd77 | |
parent | e8e6638a9ef8d81bb7c625ec890f684774f90e02 (diff) | |
parent | 68610ce9d9f2b7c1d455b529090ca0dab83a3153 (diff) |
Merge "net: add SOCK_RCU_FREE socket flag"
-rw-r--r-- | include/net/sock.h | 2 | ||||
-rw-r--r-- | net/core/sock.c | 14 |
2 files changed, 15 insertions, 1 deletions
diff --git a/include/net/sock.h b/include/net/sock.h index fca6e414f844..0e49452f5c48 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -457,6 +457,7 @@ struct sock { int (*sk_backlog_rcv)(struct sock *sk, struct sk_buff *skb); void (*sk_destruct)(struct sock *sk); + struct rcu_head sk_rcu; }; #define __sk_user_data(sk) ((*((void __rcu **)&(sk)->sk_user_data))) @@ -739,6 +740,7 @@ enum sock_flags { */ SOCK_FILTER_LOCKED, /* Filter cannot be changed anymore */ SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */ + SOCK_RCU_FREE, /* wait rcu grace period in sk_destruct() */ }; #define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) diff --git a/net/core/sock.c b/net/core/sock.c index 0d91f7dca751..fed6f3462c95 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1439,8 +1439,12 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, } EXPORT_SYMBOL(sk_alloc); -void sk_destruct(struct sock *sk) +/* Sockets having SOCK_RCU_FREE will call this function after one RCU + * grace period. This is the case for UDP sockets and TCP listeners. + */ +static void __sk_destruct(struct rcu_head *head) { + struct sock *sk = container_of(head, struct sock, sk_rcu); struct sk_filter *filter; if (sk->sk_destruct) @@ -1467,6 +1471,14 @@ void sk_destruct(struct sock *sk) sk_prot_free(sk->sk_prot_creator, sk); } +void sk_destruct(struct sock *sk) +{ + if (sock_flag(sk, SOCK_RCU_FREE)) + call_rcu(&sk->sk_rcu, __sk_destruct); + else + __sk_destruct(&sk->sk_rcu); +} + static void __sk_free(struct sock *sk) { if (unlikely(sock_diag_has_destroy_listeners(sk) && sk->sk_net_refcnt)) |