|
@@ -94,6 +94,16 @@ static struct sock_reuseport *reuseport_grow(struct sock_reuseport *reuse)
|
|
|
return more_reuse;
|
|
|
}
|
|
|
|
|
|
+static void reuseport_free_rcu(struct rcu_head *head)
|
|
|
+{
|
|
|
+ struct sock_reuseport *reuse;
|
|
|
+
|
|
|
+ reuse = container_of(head, struct sock_reuseport, rcu);
|
|
|
+ if (reuse->prog)
|
|
|
+ bpf_prog_destroy(reuse->prog);
|
|
|
+ kfree(reuse);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* reuseport_add_sock - Add a socket to the reuseport group of another.
|
|
|
* @sk: New socket to add to the group.
|
|
@@ -102,7 +112,7 @@ static struct sock_reuseport *reuseport_grow(struct sock_reuseport *reuse)
|
|
|
*/
|
|
|
int reuseport_add_sock(struct sock *sk, struct sock *sk2)
|
|
|
{
|
|
|
- struct sock_reuseport *reuse;
|
|
|
+ struct sock_reuseport *old_reuse, *reuse;
|
|
|
|
|
|
if (!rcu_access_pointer(sk2->sk_reuseport_cb)) {
|
|
|
int err = reuseport_alloc(sk2);
|
|
@@ -113,10 +123,13 @@ int reuseport_add_sock(struct sock *sk, struct sock *sk2)
|
|
|
|
|
|
spin_lock_bh(&reuseport_lock);
|
|
|
reuse = rcu_dereference_protected(sk2->sk_reuseport_cb,
|
|
|
- lockdep_is_held(&reuseport_lock)),
|
|
|
- WARN_ONCE(rcu_dereference_protected(sk->sk_reuseport_cb,
|
|
|
- lockdep_is_held(&reuseport_lock)),
|
|
|
- "socket already in reuseport group");
|
|
|
+ lockdep_is_held(&reuseport_lock));
|
|
|
+ old_reuse = rcu_dereference_protected(sk->sk_reuseport_cb,
|
|
|
+ lockdep_is_held(&reuseport_lock));
|
|
|
+ if (old_reuse && old_reuse->num_socks != 1) {
|
|
|
+ spin_unlock_bh(&reuseport_lock);
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
|
|
|
if (reuse->num_socks == reuse->max_socks) {
|
|
|
reuse = reuseport_grow(reuse);
|
|
@@ -134,19 +147,11 @@ int reuseport_add_sock(struct sock *sk, struct sock *sk2)
|
|
|
|
|
|
spin_unlock_bh(&reuseport_lock);
|
|
|
|
|
|
+ if (old_reuse)
|
|
|
+ call_rcu(&old_reuse->rcu, reuseport_free_rcu);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void reuseport_free_rcu(struct rcu_head *head)
|
|
|
-{
|
|
|
- struct sock_reuseport *reuse;
|
|
|
-
|
|
|
- reuse = container_of(head, struct sock_reuseport, rcu);
|
|
|
- if (reuse->prog)
|
|
|
- bpf_prog_destroy(reuse->prog);
|
|
|
- kfree(reuse);
|
|
|
-}
|
|
|
-
|
|
|
void reuseport_detach_sock(struct sock *sk)
|
|
|
{
|
|
|
struct sock_reuseport *reuse;
|