diff options
-rw-r--r-- | include/net/sctp/sctp.h | 14 | ||||
-rw-r--r-- | include/net/sctp/ulpevent.h | 1 | ||||
-rw-r--r-- | net/sctp/socket.c | 22 | ||||
-rw-r--r-- | net/sctp/ulpevent.c | 25 | ||||
-rw-r--r-- | net/sctp/ulpqueue.c | 2 |
5 files changed, 49 insertions, 15 deletions
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index ee68a3124076..764e3af5be93 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h | |||
@@ -139,6 +139,7 @@ int sctp_inet_listen(struct socket *sock, int backlog); | |||
139 | void sctp_write_space(struct sock *sk); | 139 | void sctp_write_space(struct sock *sk); |
140 | unsigned int sctp_poll(struct file *file, struct socket *sock, | 140 | unsigned int sctp_poll(struct file *file, struct socket *sock, |
141 | poll_table *wait); | 141 | poll_table *wait); |
142 | void sctp_sock_rfree(struct sk_buff *skb); | ||
142 | 143 | ||
143 | /* | 144 | /* |
144 | * sctp/primitive.c | 145 | * sctp/primitive.c |
@@ -444,6 +445,19 @@ static inline struct list_head *sctp_list_dequeue(struct list_head *list) | |||
444 | return result; | 445 | return result; |
445 | } | 446 | } |
446 | 447 | ||
448 | /* SCTP version of skb_set_owner_r. We need this one because | ||
449 | * of the way we have to do receive buffer accounting on bundled | ||
450 | * chunks. | ||
451 | */ | ||
452 | static inline void sctp_skb_set_owner_r(struct sk_buff *skb, struct sock *sk) | ||
453 | { | ||
454 | struct sctp_ulpevent *event = sctp_skb2event(skb); | ||
455 | |||
456 | skb->sk = sk; | ||
457 | skb->destructor = sctp_sock_rfree; | ||
458 | atomic_add(event->rmem_len, &sk->sk_rmem_alloc); | ||
459 | } | ||
460 | |||
447 | /* Tests if the list has one and only one entry. */ | 461 | /* Tests if the list has one and only one entry. */ |
448 | static inline int sctp_list_single_entry(struct list_head *head) | 462 | static inline int sctp_list_single_entry(struct list_head *head) |
449 | { | 463 | { |
diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index 6c40cfc4832d..1a4ddc1ec7d2 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h | |||
@@ -63,6 +63,7 @@ struct sctp_ulpevent { | |||
63 | __u32 cumtsn; | 63 | __u32 cumtsn; |
64 | int msg_flags; | 64 | int msg_flags; |
65 | int iif; | 65 | int iif; |
66 | unsigned int rmem_len; | ||
66 | }; | 67 | }; |
67 | 68 | ||
68 | /* Retrieve the skb this event sits inside of. */ | 69 | /* Retrieve the skb this event sits inside of. */ |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 3fe906d65069..9deec4391187 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -5362,6 +5362,20 @@ static void sctp_wfree(struct sk_buff *skb) | |||
5362 | sctp_association_put(asoc); | 5362 | sctp_association_put(asoc); |
5363 | } | 5363 | } |
5364 | 5364 | ||
5365 | /* Do accounting for the receive space on the socket. | ||
5366 | * Accounting for the association is done in ulpevent.c | ||
5367 | * We set this as a destructor for the cloned data skbs so that | ||
5368 | * accounting is done at the correct time. | ||
5369 | */ | ||
5370 | void sctp_sock_rfree(struct sk_buff *skb) | ||
5371 | { | ||
5372 | struct sock *sk = skb->sk; | ||
5373 | struct sctp_ulpevent *event = sctp_skb2event(skb); | ||
5374 | |||
5375 | atomic_sub(event->rmem_len, &sk->sk_rmem_alloc); | ||
5376 | } | ||
5377 | |||
5378 | |||
5365 | /* Helper function to wait for space in the sndbuf. */ | 5379 | /* Helper function to wait for space in the sndbuf. */ |
5366 | static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, | 5380 | static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, |
5367 | size_t msg_len) | 5381 | size_t msg_len) |
@@ -5634,10 +5648,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
5634 | sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { | 5648 | sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { |
5635 | event = sctp_skb2event(skb); | 5649 | event = sctp_skb2event(skb); |
5636 | if (event->asoc == assoc) { | 5650 | if (event->asoc == assoc) { |
5637 | sock_rfree(skb); | 5651 | sctp_sock_rfree(skb); |
5638 | __skb_unlink(skb, &oldsk->sk_receive_queue); | 5652 | __skb_unlink(skb, &oldsk->sk_receive_queue); |
5639 | __skb_queue_tail(&newsk->sk_receive_queue, skb); | 5653 | __skb_queue_tail(&newsk->sk_receive_queue, skb); |
5640 | skb_set_owner_r(skb, newsk); | 5654 | sctp_skb_set_owner_r(skb, newsk); |
5641 | } | 5655 | } |
5642 | } | 5656 | } |
5643 | 5657 | ||
@@ -5665,10 +5679,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, | |||
5665 | sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { | 5679 | sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { |
5666 | event = sctp_skb2event(skb); | 5680 | event = sctp_skb2event(skb); |
5667 | if (event->asoc == assoc) { | 5681 | if (event->asoc == assoc) { |
5668 | sock_rfree(skb); | 5682 | sctp_sock_rfree(skb); |
5669 | __skb_unlink(skb, &oldsp->pd_lobby); | 5683 | __skb_unlink(skb, &oldsp->pd_lobby); |
5670 | __skb_queue_tail(queue, skb); | 5684 | __skb_queue_tail(queue, skb); |
5671 | skb_set_owner_r(skb, newsk); | 5685 | sctp_skb_set_owner_r(skb, newsk); |
5672 | } | 5686 | } |
5673 | } | 5687 | } |
5674 | 5688 | ||
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index ee236784a6bb..a015283a9087 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c | |||
@@ -55,10 +55,13 @@ static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event); | |||
55 | 55 | ||
56 | 56 | ||
57 | /* Initialize an ULP event from an given skb. */ | 57 | /* Initialize an ULP event from an given skb. */ |
58 | SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags) | 58 | SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, |
59 | int msg_flags, | ||
60 | unsigned int len) | ||
59 | { | 61 | { |
60 | memset(event, 0, sizeof(struct sctp_ulpevent)); | 62 | memset(event, 0, sizeof(struct sctp_ulpevent)); |
61 | event->msg_flags = msg_flags; | 63 | event->msg_flags = msg_flags; |
64 | event->rmem_len = len; | ||
62 | } | 65 | } |
63 | 66 | ||
64 | /* Create a new sctp_ulpevent. */ | 67 | /* Create a new sctp_ulpevent. */ |
@@ -73,7 +76,7 @@ SCTP_STATIC struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, | |||
73 | goto fail; | 76 | goto fail; |
74 | 77 | ||
75 | event = sctp_skb2event(skb); | 78 | event = sctp_skb2event(skb); |
76 | sctp_ulpevent_init(event, msg_flags); | 79 | sctp_ulpevent_init(event, msg_flags, skb->truesize); |
77 | 80 | ||
78 | return event; | 81 | return event; |
79 | 82 | ||
@@ -101,17 +104,16 @@ static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, | |||
101 | sctp_association_hold((struct sctp_association *)asoc); | 104 | sctp_association_hold((struct sctp_association *)asoc); |
102 | skb = sctp_event2skb(event); | 105 | skb = sctp_event2skb(event); |
103 | event->asoc = (struct sctp_association *)asoc; | 106 | event->asoc = (struct sctp_association *)asoc; |
104 | atomic_add(skb->truesize, &event->asoc->rmem_alloc); | 107 | atomic_add(event->rmem_len, &event->asoc->rmem_alloc); |
105 | skb_set_owner_r(skb, asoc->base.sk); | 108 | sctp_skb_set_owner_r(skb, asoc->base.sk); |
106 | } | 109 | } |
107 | 110 | ||
108 | /* A simple destructor to give up the reference to the association. */ | 111 | /* A simple destructor to give up the reference to the association. */ |
109 | static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) | 112 | static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) |
110 | { | 113 | { |
111 | struct sctp_association *asoc = event->asoc; | 114 | struct sctp_association *asoc = event->asoc; |
112 | struct sk_buff *skb = sctp_event2skb(event); | ||
113 | 115 | ||
114 | atomic_sub(skb->truesize, &asoc->rmem_alloc); | 116 | atomic_sub(event->rmem_len, &asoc->rmem_alloc); |
115 | sctp_association_put(asoc); | 117 | sctp_association_put(asoc); |
116 | } | 118 | } |
117 | 119 | ||
@@ -372,7 +374,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( | |||
372 | 374 | ||
373 | /* Embed the event fields inside the cloned skb. */ | 375 | /* Embed the event fields inside the cloned skb. */ |
374 | event = sctp_skb2event(skb); | 376 | event = sctp_skb2event(skb); |
375 | sctp_ulpevent_init(event, MSG_NOTIFICATION); | 377 | sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); |
376 | 378 | ||
377 | sre = (struct sctp_remote_error *) | 379 | sre = (struct sctp_remote_error *) |
378 | skb_push(skb, sizeof(struct sctp_remote_error)); | 380 | skb_push(skb, sizeof(struct sctp_remote_error)); |
@@ -464,7 +466,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( | |||
464 | 466 | ||
465 | /* Embed the event fields inside the cloned skb. */ | 467 | /* Embed the event fields inside the cloned skb. */ |
466 | event = sctp_skb2event(skb); | 468 | event = sctp_skb2event(skb); |
467 | sctp_ulpevent_init(event, MSG_NOTIFICATION); | 469 | sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); |
468 | 470 | ||
469 | ssf = (struct sctp_send_failed *) | 471 | ssf = (struct sctp_send_failed *) |
470 | skb_push(skb, sizeof(struct sctp_send_failed)); | 472 | skb_push(skb, sizeof(struct sctp_send_failed)); |
@@ -682,8 +684,11 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, | |||
682 | /* Embed the event fields inside the cloned skb. */ | 684 | /* Embed the event fields inside the cloned skb. */ |
683 | event = sctp_skb2event(skb); | 685 | event = sctp_skb2event(skb); |
684 | 686 | ||
685 | /* Initialize event with flags 0. */ | 687 | /* Initialize event with flags 0 and correct length |
686 | sctp_ulpevent_init(event, 0); | 688 | * Since this is a clone of the original skb, only account for |
689 | * the data of this chunk as other chunks will be accounted separately. | ||
690 | */ | ||
691 | sctp_ulpevent_init(event, 0, skb->len + sizeof(struct sk_buff)); | ||
687 | 692 | ||
688 | sctp_ulpevent_receive_data(event, asoc); | 693 | sctp_ulpevent_receive_data(event, asoc); |
689 | 694 | ||
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 575e556aeb3e..e1d144275f97 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c | |||
@@ -309,7 +309,7 @@ static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *qu | |||
309 | if (!new) | 309 | if (!new) |
310 | return NULL; /* try again later */ | 310 | return NULL; /* try again later */ |
311 | 311 | ||
312 | new->sk = f_frag->sk; | 312 | sctp_skb_set_owner_r(new, f_frag->sk); |
313 | 313 | ||
314 | skb_shinfo(new)->frag_list = pos; | 314 | skb_shinfo(new)->frag_list = pos; |
315 | } else | 315 | } else |