diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index 7d6b1254c92d5..cfdb76e4a32e8 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -79,6 +79,14 @@ struct inet_connection_sock_af_ops { * @icsk_probes_tstamp: Probe timestamp (cleared by non-zero window ack) * @icsk_user_timeout: TCP_USER_TIMEOUT value */ + +struct icsk_ulp { + struct list_head list; + char name[16]; + const struct tcp_ulp_ops *icsk_ulp_ops; + void __rcu *icsk_ulp_data; +}; + struct inet_connection_sock { /* inet_sock has to be the first member! */ struct inet_sock icsk_inet; @@ -88,6 +96,8 @@ struct inet_connection_sock { unsigned long icsk_timeout; struct timer_list icsk_retransmit_timer; struct timer_list icsk_delack_timer; + spinlock_t icsk_ulp_lock; + struct list_head icsk_ulp_list; __u32 icsk_rto; __u32 icsk_rto_min; __u32 icsk_delack_max; @@ -361,6 +371,9 @@ static inline void inet_init_csk_locks(struct sock *sk) spin_lock_init(&icsk->icsk_accept_queue.rskq_lock); spin_lock_init(&icsk->icsk_accept_queue.fastopenq.lock); + + spin_lock_init(&icsk->icsk_ulp_lock); + INIT_LIST_HEAD(&icsk->icsk_ulp_list); } #endif /* _INET_CONNECTION_SOCK_H */ diff --git a/net/ipv4/tcp_ulp.c b/net/ipv4/tcp_ulp.c index 2aa442128630e..5662e6d8a7902 100644 --- a/net/ipv4/tcp_ulp.c +++ b/net/ipv4/tcp_ulp.c @@ -109,9 +109,23 @@ void tcp_update_ulp(struct sock *sk, struct proto *proto, icsk->icsk_ulp_ops->update(sk, proto, write_space); } +static void free_ulp_list(struct list_head *list) +{ + struct icsk_ulp *ulp; + + while (!list_empty(list)) { + ulp = list_entry(list->next, struct icsk_ulp, list); + pr_info("%s ulp->name=%s\n", __func__, ulp->name); + ulp->icsk_ulp_ops = NULL; + list_del(&ulp->list); + kfree(ulp); + } +} + void tcp_cleanup_ulp(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); + LIST_HEAD(free_list); /* No sock_owned_by_me() check here as at the time the * stack calls this function, the socket is dead and @@ -120,6 +134,12 @@ void tcp_cleanup_ulp(struct sock *sk) if (!icsk->icsk_ulp_ops) return; + spin_lock_bh(&icsk->icsk_ulp_lock); + list_splice_init(&icsk->icsk_ulp_list, &free_list); + spin_unlock_bh(&icsk->icsk_ulp_lock); + + free_ulp_list(&free_list); + if (icsk->icsk_ulp_ops->release) icsk->icsk_ulp_ops->release(sk); module_put(icsk->icsk_ulp_ops->owner); @@ -130,6 +150,7 @@ void tcp_cleanup_ulp(struct sock *sk) static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops) { struct inet_connection_sock *icsk = inet_csk(sk); + struct icsk_ulp *ulp; int err; err = -EEXIST; @@ -147,6 +168,19 @@ static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops) if (err) goto out_err; + ulp = kzalloc(sizeof(*ulp), GFP_ATOMIC); + if (!ulp) { + goto out_err; + } + + strncpy(ulp->name, ulp_ops->name, 16); + ulp->icsk_ulp_ops = ulp_ops; + ulp->icsk_ulp_data = NULL; + + spin_lock_bh(&icsk->icsk_ulp_lock); + list_add(&ulp->list, &icsk->icsk_ulp_list); + spin_unlock_bh(&icsk->icsk_ulp_lock); + icsk->icsk_ulp_ops = ulp_ops; return 0; out_err: diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 39e2cbdf38019..fb6c1e25e5aaa 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -1750,6 +1750,7 @@ static struct mptcp_subflow_context *subflow_create_ctx(struct sock *sk, { struct inet_connection_sock *icsk = inet_csk(sk); struct mptcp_subflow_context *ctx; + //struct icsk_ulp *ulp; ctx = kzalloc(sizeof(*ctx), priority); if (!ctx) @@ -1759,6 +1760,11 @@ static struct mptcp_subflow_context *subflow_create_ctx(struct sock *sk, INIT_LIST_HEAD(&ctx->node); INIT_LIST_HEAD(&ctx->delegated_node); + //spin_lock_bh(&icsk->icsk_ulp_lock); + //list_for_each_entry(ulp, &icsk->icsk_ulp_list, list) { + // pr_info("%s ulp->name=%s\n", __func__, ulp->name); + //} + //spin_unlock_bh(&icsk->icsk_ulp_lock); pr_debug("subflow=%p", ctx); ctx->tcp_sock = sk;