atomic_t ip6_frag_mem = ATOMIC_INIT(0);
/* 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, &ip6_frag_mem);
kfree_skb(skb);
}
-static inline void frag_free_queue(struct frag_queue *fq)
+static inline void frag_free_queue(struct frag_queue *fq, int *work)
{
+ if (work)
+ *work -= sizeof(struct frag_queue);
atomic_sub(sizeof(struct frag_queue), &ip6_frag_mem);
kfree(fq);
}
/* Destruction primitives. */
/* Complete destruction of fq. */
-static void ip6_frag_destroy(struct frag_queue *fq)
+static void ip6_frag_destroy(struct frag_queue *fq, int *work)
{
struct sk_buff *fp;
while (fp) {
struct sk_buff *xp = fp->next;
- frag_kfree_skb(fp);
+ frag_kfree_skb(fp, work);
fp = xp;
}
- frag_free_queue(fq);
+ frag_free_queue(fq, work);
}
-static __inline__ void fq_put(struct frag_queue *fq)
+static __inline__ void fq_put(struct frag_queue *fq, int *work)
{
if (atomic_dec_and_test(&fq->refcnt))
- ip6_frag_destroy(fq);
+ ip6_frag_destroy(fq, work);
}
/* Kill fq entry. It is not destroyed immediately,
{
struct frag_queue *fq;
struct list_head *tmp;
+ int work;
- for(;;) {
- if (atomic_read(&ip6_frag_mem) <= sysctl_ip6frag_low_thresh)
- return;
+ work = atomic_read(&ip6_frag_mem) - sysctl_ip6frag_low_thresh;
+ if (work <= 0)
+ return;
+
+ while(work > 0) {
read_lock(&ip6_frag_lock);
if (list_empty(&ip6_frag_lru_list)) {
read_unlock(&ip6_frag_lock);
fq_kill(fq);
spin_unlock(&fq->lock);
- fq_put(fq);
+ fq_put(fq, &work);
IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
}
}
}
out:
spin_unlock(&fq->lock);
- fq_put(fq);
+ fq_put(fq, NULL);
}
/* Creation primitives. */
atomic_inc(&fq->refcnt);
write_unlock(&ip6_frag_lock);
fq_in->last_in |= COMPLETE;
- fq_put(fq_in);
+ fq_put(fq_in, NULL);
return fq;
}
}
fq->fragments = next;
fq->meat -= free_it->len;
- frag_kfree_skb(free_it);
+ frag_kfree_skb(free_it, NULL);
}
}
head->next = NULL;
head->dev = dev;
head->stamp = fq->stamp;
- head->nh.ipv6h->payload_len = ntohs(payload_len);
+ head->nh.ipv6h->payload_len = htons(payload_len);
*skb_in = head;
ret = ip6_frag_reasm(fq, skbp, nhoffp, dev);
spin_unlock(&fq->lock);
- fq_put(fq);
+ fq_put(fq, NULL);
return ret;
}