X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fip_fragment.c;h=df083ded1109392721501a958087e9e652748e6f;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=375caffe0c1943c9088269ed50e450cf3264b3ac;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 375caffe0..df083ded1 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -169,14 +169,18 @@ static void ipfrag_secret_rebuild(unsigned long dummy) atomic_t ip_frag_mem = ATOMIC_INIT(0); /* Memory used for fragments */ /* Memory Tracking Functions. */ -static __inline__ void frag_kfree_skb(struct sk_buff *skb) +static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work) { + if (work) + *work -= skb->truesize; atomic_sub(skb->truesize, &ip_frag_mem); kfree_skb(skb); } -static __inline__ void frag_free_queue(struct ipq *qp) +static __inline__ void frag_free_queue(struct ipq *qp, int *work) { + if (work) + *work -= sizeof(struct ipq); atomic_sub(sizeof(struct ipq), &ip_frag_mem); kfree(qp); } @@ -195,7 +199,7 @@ static __inline__ struct ipq *frag_alloc_queue(void) /* Destruction primitives. */ /* Complete destruction of ipq. */ -static void ip_frag_destroy(struct ipq *qp) +static void ip_frag_destroy(struct ipq *qp, int *work) { struct sk_buff *fp; @@ -207,18 +211,18 @@ static void ip_frag_destroy(struct ipq *qp) while (fp) { struct sk_buff *xp = fp->next; - frag_kfree_skb(fp); + frag_kfree_skb(fp, work); fp = xp; } /* Finally, release the queue descriptor itself. */ - frag_free_queue(qp); + frag_free_queue(qp, work); } -static __inline__ void ipq_put(struct ipq *ipq) +static __inline__ void ipq_put(struct ipq *ipq, int *work) { if (atomic_dec_and_test(&ipq->refcnt)) - ip_frag_destroy(ipq); + ip_frag_destroy(ipq, work); } /* Kill ipq entry. It is not destroyed immediately, @@ -237,16 +241,19 @@ static void ipq_kill(struct ipq *ipq) } /* Memory limiting on fragments. Evictor trashes the oldest - * fragment queue until we are back under the low threshold. + * fragment queue until we are back under the threshold. */ -static void ip_evictor(void) +static void __ip_evictor(int threshold) { struct ipq *qp; struct list_head *tmp; + int work; - for(;;) { - if (atomic_read(&ip_frag_mem) <= sysctl_ipfrag_low_thresh) - return; + work = atomic_read(&ip_frag_mem) - threshold; + if (work <= 0) + return; + + while (work > 0) { read_lock(&ipfrag_lock); if (list_empty(&ipq_lru_list)) { read_unlock(&ipfrag_lock); @@ -262,11 +269,16 @@ static void ip_evictor(void) ipq_kill(qp); spin_unlock(&qp->lock); - ipq_put(qp); - IP_INC_STATS_BH(IpReasmFails); + ipq_put(qp, &work); + IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); } } +static inline void ip_evictor(void) +{ + __ip_evictor(sysctl_ipfrag_low_thresh); +} + /* * Oops, a fragment queue timed out. Kill it and send an ICMP reply. */ @@ -281,8 +293,8 @@ static void ip_expire(unsigned long arg) ipq_kill(qp); - IP_INC_STATS_BH(IpReasmTimeout); - IP_INC_STATS_BH(IpReasmFails); + IP_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT); + IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) { struct sk_buff *head = qp->fragments; @@ -294,7 +306,7 @@ static void ip_expire(unsigned long arg) } out: spin_unlock(&qp->lock); - ipq_put(qp); + ipq_put(qp, NULL); } /* Creation primitives. */ @@ -317,7 +329,7 @@ static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in) atomic_inc(&qp->refcnt); write_unlock(&ipfrag_lock); qp_in->last_in |= COMPLETE; - ipq_put(qp_in); + ipq_put(qp_in, NULL); return qp; } } @@ -506,7 +518,7 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb) qp->fragments = next; qp->meat -= free_it->len; - frag_kfree_skb(free_it); + frag_kfree_skb(free_it, NULL); } } @@ -609,7 +621,7 @@ static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev) iph = head->nh.iph; iph->frag_off = 0; iph->tot_len = htons(len); - IP_INC_STATS_BH(IpReasmOKs); + IP_INC_STATS_BH(IPSTATS_MIB_REASMOKS); qp->fragments = NULL; return head; @@ -625,7 +637,7 @@ out_oversize: "Oversized IP packet from %d.%d.%d.%d.\n", NIPQUAD(qp->saddr)); out_fail: - IP_INC_STATS_BH(IpReasmFails); + IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); return NULL; } @@ -636,7 +648,7 @@ struct sk_buff *ip_defrag(struct sk_buff *skb) struct ipq *qp; struct net_device *dev; - IP_INC_STATS_BH(IpReasmReqds); + IP_INC_STATS_BH(IPSTATS_MIB_REASMREQDS); /* Start by cleaning up the memory. */ if (atomic_read(&ip_frag_mem) > sysctl_ipfrag_high_thresh) @@ -657,11 +669,11 @@ struct sk_buff *ip_defrag(struct sk_buff *skb) ret = ip_frag_reasm(qp, dev); spin_unlock(&qp->lock); - ipq_put(qp); + ipq_put(qp, NULL); return ret; } - IP_INC_STATS_BH(IpReasmFails); + IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); kfree_skb(skb); return NULL; } @@ -677,4 +689,10 @@ void ipfrag_init(void) add_timer(&ipfrag_secret_timer); } +void ipfrag_flush(void) +{ + __ip_evictor(0); +} + EXPORT_SYMBOL(ip_defrag); +EXPORT_SYMBOL(ipfrag_flush);