summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-11-28 23:58:04 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2016-11-28 23:58:04 -0800
commit2be8fc81c3adef891480d3abd19639860d838443 (patch)
tree91f4720b3d455de6104a0bfca5f112d29fcacd77
parente8e6638a9ef8d81bb7c625ec890f684774f90e02 (diff)
parent68610ce9d9f2b7c1d455b529090ca0dab83a3153 (diff)
Merge "net: add SOCK_RCU_FREE socket flag"
-rw-r--r--include/net/sock.h2
-rw-r--r--net/core/sock.c14
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))