diff options
author | Tsutomu Fujii <t-fujii@nb.jp.nec.com> | 2007-04-17 15:49:53 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-17 16:13:37 -0400 |
commit | ea2bc483ff5caada7c4aa0d5fbf87d3a6590273d (patch) | |
tree | 2dea10c6646a961568b3108f2aad0572113576cd /net/sctp/socket.c | |
parent | c2ecba71717c4f60671175fd26083c35a4b9ad58 (diff) |
[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>
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 48 |
1 files changed, 44 insertions, 4 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 536298c2eda2..523e73ee354a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -5638,6 +5638,36 @@ void sctp_wait_for_close(struct sock *sk, long timeout) | |||
5638 | finish_wait(sk->sk_sleep, &wait); | 5638 | finish_wait(sk->sk_sleep, &wait); |
5639 | } | 5639 | } |
5640 | 5640 | ||
5641 | static void sctp_sock_rfree_frag(struct sk_buff *skb) | ||
5642 | { | ||
5643 | struct sk_buff *frag; | ||
5644 | |||
5645 | if (!skb->data_len) | ||
5646 | goto done; | ||
5647 | |||
5648 | /* Don't forget the fragments. */ | ||
5649 | for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) | ||
5650 | sctp_sock_rfree_frag(frag); | ||
5651 | |||
5652 | done: | ||
5653 | sctp_sock_rfree(skb); | ||
5654 | } | ||
5655 | |||
5656 | static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk) | ||
5657 | { | ||
5658 | struct sk_buff *frag; | ||
5659 | |||
5660 | if (!skb->data_len) | ||
5661 | goto done; | ||
5662 | |||
5663 | /* Don't forget the fragments. */ | ||
5664 | for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) | ||
5665 | sctp_skb_set_owner_r_frag(frag, sk); | ||
5666 | |||
5667 | done: | ||
5668 | sctp_skb_set_owner_r(skb, sk); | ||
5669 | } | ||
5670 | |||
5641 | /* Populate the fields of the newsk from the oldsk and migrate the assoc | 5671 | /* Populate the fields of the newsk from the oldsk and migrate the assoc |
5642 | * and its messages to the newsk. | 5672 | * and its messages to the newsk. |
5643 | */ | 5673 | */ |
@@ -5692,10 +5722,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
5692 | sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { | 5722 | sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { |
5693 | event = sctp_skb2event(skb); | 5723 | event = sctp_skb2event(skb); |
5694 | if (event->asoc == assoc) { | 5724 | if (event->asoc == assoc) { |
5695 | sctp_sock_rfree(skb); | 5725 | sctp_sock_rfree_frag(skb); |
5696 | __skb_unlink(skb, &oldsk->sk_receive_queue); | 5726 | __skb_unlink(skb, &oldsk->sk_receive_queue); |
5697 | __skb_queue_tail(&newsk->sk_receive_queue, skb); | 5727 | __skb_queue_tail(&newsk->sk_receive_queue, skb); |
5698 | sctp_skb_set_owner_r(skb, newsk); | 5728 | sctp_skb_set_owner_r_frag(skb, newsk); |
5699 | } | 5729 | } |
5700 | } | 5730 | } |
5701 | 5731 | ||
@@ -5723,10 +5753,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
5723 | sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { | 5753 | sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { |
5724 | event = sctp_skb2event(skb); | 5754 | event = sctp_skb2event(skb); |
5725 | if (event->asoc == assoc) { | 5755 | if (event->asoc == assoc) { |
5726 | sctp_sock_rfree(skb); | 5756 | sctp_sock_rfree_frag(skb); |
5727 | __skb_unlink(skb, &oldsp->pd_lobby); | 5757 | __skb_unlink(skb, &oldsp->pd_lobby); |
5728 | __skb_queue_tail(queue, skb); | 5758 | __skb_queue_tail(queue, skb); |
5729 | sctp_skb_set_owner_r(skb, newsk); | 5759 | sctp_skb_set_owner_r_frag(skb, newsk); |
5730 | } | 5760 | } |
5731 | } | 5761 | } |
5732 | 5762 | ||
@@ -5738,6 +5768,16 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
5738 | 5768 | ||
5739 | } | 5769 | } |
5740 | 5770 | ||
5771 | sctp_skb_for_each(skb, &assoc->ulpq.reasm, tmp) { | ||
5772 | sctp_sock_rfree_frag(skb); | ||
5773 | sctp_skb_set_owner_r_frag(skb, newsk); | ||
5774 | } | ||
5775 | |||
5776 | sctp_skb_for_each(skb, &assoc->ulpq.lobby, tmp) { | ||
5777 | sctp_sock_rfree_frag(skb); | ||
5778 | sctp_skb_set_owner_r_frag(skb, newsk); | ||
5779 | } | ||
5780 | |||
5741 | /* Set the type of socket to indicate that it is peeled off from the | 5781 | /* Set the type of socket to indicate that it is peeled off from the |
5742 | * original UDP-style socket or created with the accept() call on a | 5782 | * original UDP-style socket or created with the accept() call on a |
5743 | * TCP-style socket.. | 5783 | * TCP-style socket.. |