aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesper Dangaard Brouer <brouer@redhat.com>2013-01-28 18:45:12 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-29 13:36:24 -0500
commitd433673e5f9180e05a770c4b2ab18c08ad51cc21 (patch)
tree7d71bb8483724418e6a4f48cc4099a8722c704c8
parent6e34a8b37aca63f109bf990d46131ee07206f5f1 (diff)
net: frag helper functions for mem limit tracking
This change is primarily a preparation to ease the extension of memory limit tracking. The change does reduce the number atomic operation, during freeing of a frag queue. This does introduce a some performance improvement, as these atomic operations are at the core of the performance problems seen on NUMA systems. Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/inet_frag.h27
-rw-r--r--include/net/ipv6.h2
-rw-r--r--net/ipv4/inet_fragment.c25
-rw-r--r--net/ipv4/ip_fragment.c24
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c6
-rw-r--r--net/ipv6/reassembly.c6
6 files changed, 57 insertions, 33 deletions
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 8e4c42523f59..f2fabc2a79de 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -79,4 +79,31 @@ static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f
79 inet_frag_destroy(q, f, NULL); 79 inet_frag_destroy(q, f, NULL);
80} 80}
81 81
82/* Memory Tracking Functions. */
83
84static inline int frag_mem_limit(struct netns_frags *nf)
85{
86 return atomic_read(&nf->mem);
87}
88
89static inline void sub_frag_mem_limit(struct inet_frag_queue *q, int i)
90{
91 atomic_sub(i, &q->net->mem);
92}
93
94static inline void add_frag_mem_limit(struct inet_frag_queue *q, int i)
95{
96 atomic_add(i, &q->net->mem);
97}
98
99static inline void init_frag_mem_limit(struct netns_frags *nf)
100{
101 atomic_set(&nf->mem, 0);
102}
103
104static inline int sum_frag_mem_limit(struct netns_frags *nf)
105{
106 return atomic_read(&nf->mem);
107}
108
82#endif 109#endif
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index c1878f7049c8..dc30b60975ef 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -288,7 +288,7 @@ static inline int ip6_frag_nqueues(struct net *net)
288 288
289static inline int ip6_frag_mem(struct net *net) 289static inline int ip6_frag_mem(struct net *net)
290{ 290{
291 return atomic_read(&net->ipv6.frags.mem); 291 return sum_frag_mem_limit(&net->ipv6.frags);
292} 292}
293#endif 293#endif
294 294
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 4750d2b74d79..e348c849c5a3 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -73,7 +73,7 @@ EXPORT_SYMBOL(inet_frags_init);
73void inet_frags_init_net(struct netns_frags *nf) 73void inet_frags_init_net(struct netns_frags *nf)
74{ 74{
75 nf->nqueues = 0; 75 nf->nqueues = 0;
76 atomic_set(&nf->mem, 0); 76 init_frag_mem_limit(nf);
77 INIT_LIST_HEAD(&nf->lru_list); 77 INIT_LIST_HEAD(&nf->lru_list);
78} 78}
79EXPORT_SYMBOL(inet_frags_init_net); 79EXPORT_SYMBOL(inet_frags_init_net);
@@ -117,12 +117,8 @@ void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f)
117EXPORT_SYMBOL(inet_frag_kill); 117EXPORT_SYMBOL(inet_frag_kill);
118 118
119static inline void frag_kfree_skb(struct netns_frags *nf, struct inet_frags *f, 119static inline void frag_kfree_skb(struct netns_frags *nf, struct inet_frags *f,
120 struct sk_buff *skb, int *work) 120 struct sk_buff *skb)
121{ 121{
122 if (work)
123 *work -= skb->truesize;
124
125 atomic_sub(skb->truesize, &nf->mem);
126 if (f->skb_free) 122 if (f->skb_free)
127 f->skb_free(skb); 123 f->skb_free(skb);
128 kfree_skb(skb); 124 kfree_skb(skb);
@@ -133,6 +129,7 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f,
133{ 129{
134 struct sk_buff *fp; 130 struct sk_buff *fp;
135 struct netns_frags *nf; 131 struct netns_frags *nf;
132 unsigned int sum, sum_truesize = 0;
136 133
137 WARN_ON(!(q->last_in & INET_FRAG_COMPLETE)); 134 WARN_ON(!(q->last_in & INET_FRAG_COMPLETE));
138 WARN_ON(del_timer(&q->timer) != 0); 135 WARN_ON(del_timer(&q->timer) != 0);
@@ -143,13 +140,14 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f,
143 while (fp) { 140 while (fp) {
144 struct sk_buff *xp = fp->next; 141 struct sk_buff *xp = fp->next;
145 142
146 frag_kfree_skb(nf, f, fp, work); 143 sum_truesize += fp->truesize;
144 frag_kfree_skb(nf, f, fp);
147 fp = xp; 145 fp = xp;
148 } 146 }
149 147 sum = sum_truesize + f->qsize;
150 if (work) 148 if (work)
151 *work -= f->qsize; 149 *work -= sum;
152 atomic_sub(f->qsize, &nf->mem); 150 sub_frag_mem_limit(q, sum);
153 151
154 if (f->destructor) 152 if (f->destructor)
155 f->destructor(q); 153 f->destructor(q);
@@ -164,11 +162,11 @@ int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force)
164 int work, evicted = 0; 162 int work, evicted = 0;
165 163
166 if (!force) { 164 if (!force) {
167 if (atomic_read(&nf->mem) <= nf->high_thresh) 165 if (frag_mem_limit(nf) <= nf->high_thresh)
168 return 0; 166 return 0;
169 } 167 }
170 168
171 work = atomic_read(&nf->mem) - nf->low_thresh; 169 work = frag_mem_limit(nf) - nf->low_thresh;
172 while (work > 0) { 170 while (work > 0) {
173 read_lock(&f->lock); 171 read_lock(&f->lock);
174 if (list_empty(&nf->lru_list)) { 172 if (list_empty(&nf->lru_list)) {
@@ -250,7 +248,8 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf,
250 248
251 q->net = nf; 249 q->net = nf;
252 f->constructor(q, arg); 250 f->constructor(q, arg);
253 atomic_add(f->qsize, &nf->mem); 251 add_frag_mem_limit(q, f->qsize);
252
254 setup_timer(&q->timer, f->frag_expire, (unsigned long)q); 253 setup_timer(&q->timer, f->frag_expire, (unsigned long)q);
255 spin_lock_init(&q->lock); 254 spin_lock_init(&q->lock);
256 atomic_set(&q->refcnt, 1); 255 atomic_set(&q->refcnt, 1);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index f55a4e61bfb8..927fe58caf46 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -122,7 +122,7 @@ int ip_frag_nqueues(struct net *net)
122 122
123int ip_frag_mem(struct net *net) 123int ip_frag_mem(struct net *net)
124{ 124{
125 return atomic_read(&net->ipv4.frags.mem); 125 return sum_frag_mem_limit(&net->ipv4.frags);
126} 126}
127 127
128static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, 128static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
@@ -161,13 +161,6 @@ static bool ip4_frag_match(struct inet_frag_queue *q, void *a)
161 qp->user == arg->user; 161 qp->user == arg->user;
162} 162}
163 163
164/* Memory Tracking Functions. */
165static void frag_kfree_skb(struct netns_frags *nf, struct sk_buff *skb)
166{
167 atomic_sub(skb->truesize, &nf->mem);
168 kfree_skb(skb);
169}
170
171static void ip4_frag_init(struct inet_frag_queue *q, void *a) 164static void ip4_frag_init(struct inet_frag_queue *q, void *a)
172{ 165{
173 struct ipq *qp = container_of(q, struct ipq, q); 166 struct ipq *qp = container_of(q, struct ipq, q);
@@ -340,6 +333,7 @@ static inline int ip_frag_too_far(struct ipq *qp)
340static int ip_frag_reinit(struct ipq *qp) 333static int ip_frag_reinit(struct ipq *qp)
341{ 334{
342 struct sk_buff *fp; 335 struct sk_buff *fp;
336 unsigned int sum_truesize = 0;
343 337
344 if (!mod_timer(&qp->q.timer, jiffies + qp->q.net->timeout)) { 338 if (!mod_timer(&qp->q.timer, jiffies + qp->q.net->timeout)) {
345 atomic_inc(&qp->q.refcnt); 339 atomic_inc(&qp->q.refcnt);
@@ -349,9 +343,12 @@ static int ip_frag_reinit(struct ipq *qp)
349 fp = qp->q.fragments; 343 fp = qp->q.fragments;
350 do { 344 do {
351 struct sk_buff *xp = fp->next; 345 struct sk_buff *xp = fp->next;
352 frag_kfree_skb(qp->q.net, fp); 346
347 sum_truesize += fp->truesize;
348 kfree_skb(fp);
353 fp = xp; 349 fp = xp;
354 } while (fp); 350 } while (fp);
351 sub_frag_mem_limit(&qp->q, sum_truesize);
355 352
356 qp->q.last_in = 0; 353 qp->q.last_in = 0;
357 qp->q.len = 0; 354 qp->q.len = 0;
@@ -496,7 +493,8 @@ found:
496 qp->q.fragments = next; 493 qp->q.fragments = next;
497 494
498 qp->q.meat -= free_it->len; 495 qp->q.meat -= free_it->len;
499 frag_kfree_skb(qp->q.net, free_it); 496 sub_frag_mem_limit(&qp->q, free_it->truesize);
497 kfree_skb(free_it);
500 } 498 }
501 } 499 }
502 500
@@ -519,7 +517,7 @@ found:
519 qp->q.stamp = skb->tstamp; 517 qp->q.stamp = skb->tstamp;
520 qp->q.meat += skb->len; 518 qp->q.meat += skb->len;
521 qp->ecn |= ecn; 519 qp->ecn |= ecn;
522 atomic_add(skb->truesize, &qp->q.net->mem); 520 add_frag_mem_limit(&qp->q, skb->truesize);
523 if (offset == 0) 521 if (offset == 0)
524 qp->q.last_in |= INET_FRAG_FIRST_IN; 522 qp->q.last_in |= INET_FRAG_FIRST_IN;
525 523
@@ -617,7 +615,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
617 head->len -= clone->len; 615 head->len -= clone->len;
618 clone->csum = 0; 616 clone->csum = 0;
619 clone->ip_summed = head->ip_summed; 617 clone->ip_summed = head->ip_summed;
620 atomic_add(clone->truesize, &qp->q.net->mem); 618 add_frag_mem_limit(&qp->q, clone->truesize);
621 } 619 }
622 620
623 skb_push(head, head->data - skb_network_header(head)); 621 skb_push(head, head->data - skb_network_header(head));
@@ -645,7 +643,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
645 } 643 }
646 fp = next; 644 fp = next;
647 } 645 }
648 atomic_sub(sum_truesize, &qp->q.net->mem); 646 sub_frag_mem_limit(&qp->q, sum_truesize);
649 647
650 head->next = NULL; 648 head->next = NULL;
651 head->dev = dev; 649 head->dev = dev;
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 3dacecc99065..07ef2949c946 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -319,7 +319,7 @@ found:
319 fq->q.meat += skb->len; 319 fq->q.meat += skb->len;
320 if (payload_len > fq->q.max_size) 320 if (payload_len > fq->q.max_size)
321 fq->q.max_size = payload_len; 321 fq->q.max_size = payload_len;
322 atomic_add(skb->truesize, &fq->q.net->mem); 322 add_frag_mem_limit(&fq->q, skb->truesize);
323 323
324 /* The first fragment. 324 /* The first fragment.
325 * nhoffset is obtained from the first fragment, of course. 325 * nhoffset is obtained from the first fragment, of course.
@@ -398,7 +398,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev)
398 clone->ip_summed = head->ip_summed; 398 clone->ip_summed = head->ip_summed;
399 399
400 NFCT_FRAG6_CB(clone)->orig = NULL; 400 NFCT_FRAG6_CB(clone)->orig = NULL;
401 atomic_add(clone->truesize, &fq->q.net->mem); 401 add_frag_mem_limit(&fq->q, clone->truesize);
402 } 402 }
403 403
404 /* We have to remove fragment header from datagram and to relocate 404 /* We have to remove fragment header from datagram and to relocate
@@ -422,7 +422,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev)
422 head->csum = csum_add(head->csum, fp->csum); 422 head->csum = csum_add(head->csum, fp->csum);
423 head->truesize += fp->truesize; 423 head->truesize += fp->truesize;
424 } 424 }
425 atomic_sub(head->truesize, &fq->q.net->mem); 425 sub_frag_mem_limit(&fq->q, head->truesize);
426 426
427 head->local_df = 1; 427 head->local_df = 1;
428 head->next = NULL; 428 head->next = NULL;
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index e5253ec9e0fc..18cb8defcdb2 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -327,7 +327,7 @@ found:
327 } 327 }
328 fq->q.stamp = skb->tstamp; 328 fq->q.stamp = skb->tstamp;
329 fq->q.meat += skb->len; 329 fq->q.meat += skb->len;
330 atomic_add(skb->truesize, &fq->q.net->mem); 330 add_frag_mem_limit(&fq->q, skb->truesize);
331 331
332 /* The first fragment. 332 /* The first fragment.
333 * nhoffset is obtained from the first fragment, of course. 333 * nhoffset is obtained from the first fragment, of course.
@@ -429,7 +429,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
429 head->len -= clone->len; 429 head->len -= clone->len;
430 clone->csum = 0; 430 clone->csum = 0;
431 clone->ip_summed = head->ip_summed; 431 clone->ip_summed = head->ip_summed;
432 atomic_add(clone->truesize, &fq->q.net->mem); 432 add_frag_mem_limit(&fq->q, clone->truesize);
433 } 433 }
434 434
435 /* We have to remove fragment header from datagram and to relocate 435 /* We have to remove fragment header from datagram and to relocate
@@ -467,7 +467,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
467 } 467 }
468 fp = next; 468 fp = next;
469 } 469 }
470 atomic_sub(sum_truesize, &fq->q.net->mem); 470 sub_frag_mem_limit(&fq->q, sum_truesize);
471 471
472 head->next = NULL; 472 head->next = NULL;
473 head->dev = dev; 473 head->dev = dev;