[SCTP]: Fix assertion (!atomic_read(&sk->sk_rmem_alloc)) failed message
In current implementation, LKSCTP does receive buffer accounting for data in sctp_receive_queue and pd_lobby. However, LKSCTP don't do accounting for data in frag_list when data is fragmented. In addition, LKSCTP doesn't do accounting for data in reasm and lobby queue in structure sctp_ulpq. When there are date in these queue, assertion failed message is printed in inet_sock_destruct because sk_rmem_alloc of oldsk does not become 0 when socket is destroyed. Signed-off-by: Tsutomu Fujii <t-fujii@nb.jp.nec.com> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
c2ecba7171
commit
ea2bc483ff
1 changed files with 44 additions and 4 deletions
|
@ -5638,6 +5638,36 @@ void sctp_wait_for_close(struct sock *sk, long timeout)
|
|||
finish_wait(sk->sk_sleep, &wait);
|
||||
}
|
||||
|
||||
static void sctp_sock_rfree_frag(struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *frag;
|
||||
|
||||
if (!skb->data_len)
|
||||
goto done;
|
||||
|
||||
/* Don't forget the fragments. */
|
||||
for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next)
|
||||
sctp_sock_rfree_frag(frag);
|
||||
|
||||
done:
|
||||
sctp_sock_rfree(skb);
|
||||
}
|
||||
|
||||
static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk)
|
||||
{
|
||||
struct sk_buff *frag;
|
||||
|
||||
if (!skb->data_len)
|
||||
goto done;
|
||||
|
||||
/* Don't forget the fragments. */
|
||||
for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next)
|
||||
sctp_skb_set_owner_r_frag(frag, sk);
|
||||
|
||||
done:
|
||||
sctp_skb_set_owner_r(skb, sk);
|
||||
}
|
||||
|
||||
/* Populate the fields of the newsk from the oldsk and migrate the assoc
|
||||
* and its messages to the newsk.
|
||||
*/
|
||||
|
@ -5692,10 +5722,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
|
|||
sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
|
||||
event = sctp_skb2event(skb);
|
||||
if (event->asoc == assoc) {
|
||||
sctp_sock_rfree(skb);
|
||||
sctp_sock_rfree_frag(skb);
|
||||
__skb_unlink(skb, &oldsk->sk_receive_queue);
|
||||
__skb_queue_tail(&newsk->sk_receive_queue, skb);
|
||||
sctp_skb_set_owner_r(skb, newsk);
|
||||
sctp_skb_set_owner_r_frag(skb, newsk);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5723,10 +5753,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
|
|||
sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
|
||||
event = sctp_skb2event(skb);
|
||||
if (event->asoc == assoc) {
|
||||
sctp_sock_rfree(skb);
|
||||
sctp_sock_rfree_frag(skb);
|
||||
__skb_unlink(skb, &oldsp->pd_lobby);
|
||||
__skb_queue_tail(queue, skb);
|
||||
sctp_skb_set_owner_r(skb, newsk);
|
||||
sctp_skb_set_owner_r_frag(skb, newsk);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5738,6 +5768,16 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
|
|||
|
||||
}
|
||||
|
||||
sctp_skb_for_each(skb, &assoc->ulpq.reasm, tmp) {
|
||||
sctp_sock_rfree_frag(skb);
|
||||
sctp_skb_set_owner_r_frag(skb, newsk);
|
||||
}
|
||||
|
||||
sctp_skb_for_each(skb, &assoc->ulpq.lobby, tmp) {
|
||||
sctp_sock_rfree_frag(skb);
|
||||
sctp_skb_set_owner_r_frag(skb, newsk);
|
||||
}
|
||||
|
||||
/* Set the type of socket to indicate that it is peeled off from the
|
||||
* original UDP-style socket or created with the accept() call on a
|
||||
* TCP-style socket..
|
||||
|
|
Loading…
Reference in a new issue