diff options
author | Jesper Dangaard Brouer <brouer@redhat.com> | 2013-01-28 18:45:12 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-01-29 13:36:24 -0500 |
commit | d433673e5f9180e05a770c4b2ab18c08ad51cc21 (patch) | |
tree | 7d71bb8483724418e6a4f48cc4099a8722c704c8 | |
parent | 6e34a8b37aca63f109bf990d46131ee07206f5f1 (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.h | 27 | ||||
-rw-r--r-- | include/net/ipv6.h | 2 | ||||
-rw-r--r-- | net/ipv4/inet_fragment.c | 25 | ||||
-rw-r--r-- | net/ipv4/ip_fragment.c | 24 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_reasm.c | 6 | ||||
-rw-r--r-- | net/ipv6/reassembly.c | 6 |
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 | |||
84 | static inline int frag_mem_limit(struct netns_frags *nf) | ||
85 | { | ||
86 | return atomic_read(&nf->mem); | ||
87 | } | ||
88 | |||
89 | static inline void sub_frag_mem_limit(struct inet_frag_queue *q, int i) | ||
90 | { | ||
91 | atomic_sub(i, &q->net->mem); | ||
92 | } | ||
93 | |||
94 | static inline void add_frag_mem_limit(struct inet_frag_queue *q, int i) | ||
95 | { | ||
96 | atomic_add(i, &q->net->mem); | ||
97 | } | ||
98 | |||
99 | static inline void init_frag_mem_limit(struct netns_frags *nf) | ||
100 | { | ||
101 | atomic_set(&nf->mem, 0); | ||
102 | } | ||
103 | |||
104 | static 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 | ||
289 | static inline int ip6_frag_mem(struct net *net) | 289 | static 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); | |||
73 | void inet_frags_init_net(struct netns_frags *nf) | 73 | void 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 | } |
79 | EXPORT_SYMBOL(inet_frags_init_net); | 79 | EXPORT_SYMBOL(inet_frags_init_net); |
@@ -117,12 +117,8 @@ void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f) | |||
117 | EXPORT_SYMBOL(inet_frag_kill); | 117 | EXPORT_SYMBOL(inet_frag_kill); |
118 | 118 | ||
119 | static inline void frag_kfree_skb(struct netns_frags *nf, struct inet_frags *f, | 119 | static 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 | ||
123 | int ip_frag_mem(struct net *net) | 123 | int 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 | ||
128 | static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | 128 | static 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. */ | ||
165 | static 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 | |||
171 | static void ip4_frag_init(struct inet_frag_queue *q, void *a) | 164 | static 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) | |||
340 | static int ip_frag_reinit(struct ipq *qp) | 333 | static 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; |