aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/sctp/sctp.h14
-rw-r--r--include/net/sctp/ulpevent.h1
-rw-r--r--net/sctp/socket.c22
-rw-r--r--net/sctp/ulpevent.c25
-rw-r--r--net/sctp/ulpqueue.c2
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);
139void sctp_write_space(struct sock *sk); 139void sctp_write_space(struct sock *sk);
140unsigned int sctp_poll(struct file *file, struct socket *sock, 140unsigned int sctp_poll(struct file *file, struct socket *sock,
141 poll_table *wait); 141 poll_table *wait);
142void 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 */
452static 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. */
448static inline int sctp_list_single_entry(struct list_head *head) 462static 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 */
5370void 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. */
5366static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, 5380static 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. */
58SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags) 58SCTP_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. */
109static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) 112static 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