Skip to content

Commit

Permalink
[SCTP]: Fix assertion (!atomic_read(&sk->sk_rmem_alloc)) failed message
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Tsutomu Fujii authored and David S. Miller committed Apr 17, 2007
1 parent c2ecba7 commit ea2bc48
Showing 1 changed file with 44 additions and 4 deletions.
48 changes: 44 additions & 4 deletions net/sctp/socket.c
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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..
Expand Down

0 comments on commit ea2bc48

Please sign in to comment.