summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/inet_fragment.c32
-rw-r--r--net/ipv4/ip_fragment.c30
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c29
-rw-r--r--net/ipv6/reassembly.c30
4 files changed, 41 insertions, 80 deletions
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 15fb2c4a36a..484cf512858 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -140,3 +140,35 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f,
}
EXPORT_SYMBOL(inet_frag_destroy);
+
+int inet_frag_evictor(struct inet_frags *f)
+{
+ struct inet_frag_queue *q;
+ int work, evicted = 0;
+
+ work = atomic_read(&f->mem) - f->ctl->low_thresh;
+ while (work > 0) {
+ read_lock(&f->lock);
+ if (list_empty(&f->lru_list)) {
+ read_unlock(&f->lock);
+ break;
+ }
+
+ q = list_first_entry(&f->lru_list,
+ struct inet_frag_queue, lru_list);
+ atomic_inc(&q->refcnt);
+ read_unlock(&f->lock);
+
+ spin_lock(&q->lock);
+ if (!(q->last_in & COMPLETE))
+ inet_frag_kill(q, f);
+ spin_unlock(&q->lock);
+
+ if (atomic_dec_and_test(&q->refcnt))
+ inet_frag_destroy(q, f, &work);
+ evicted++;
+ }
+
+ return evicted;
+}
+EXPORT_SYMBOL(inet_frag_evictor);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index e8736632094..ee6e0415962 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -174,33 +174,11 @@ static void ipq_kill(struct ipq *ipq)
*/
static void ip_evictor(void)
{
- struct ipq *qp;
- struct list_head *tmp;
- int work;
-
- work = atomic_read(&ip4_frags.mem) - ip4_frags_ctl.low_thresh;
- if (work <= 0)
- return;
-
- while (work > 0) {
- read_lock(&ip4_frags.lock);
- if (list_empty(&ip4_frags.lru_list)) {
- read_unlock(&ip4_frags.lock);
- return;
- }
- tmp = ip4_frags.lru_list.next;
- qp = list_entry(tmp, struct ipq, q.lru_list);
- atomic_inc(&qp->q.refcnt);
- read_unlock(&ip4_frags.lock);
+ int evicted;
- spin_lock(&qp->q.lock);
- if (!(qp->q.last_in&COMPLETE))
- ipq_kill(qp);
- spin_unlock(&qp->q.lock);
-
- ipq_put(qp, &work);
- IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
- }
+ evicted = inet_frag_evictor(&ip4_frags);
+ if (evicted)
+ IP_ADD_STATS_BH(IPSTATS_MIB_REASMFAILS, evicted);
}
/*
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 785f5cda188..e4fbe5ba88f 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -163,34 +163,7 @@ static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq)
static void nf_ct_frag6_evictor(void)
{
- struct nf_ct_frag6_queue *fq;
- struct list_head *tmp;
- unsigned int work;
-
- work = atomic_read(&nf_frags.mem);
- if (work <= nf_frags_ctl.low_thresh)
- return;
-
- work -= nf_frags_ctl.low_thresh;
- while (work > 0) {
- read_lock(&nf_frags.lock);
- if (list_empty(&nf_frags.lru_list)) {
- read_unlock(&nf_frags.lock);
- return;
- }
- tmp = nf_frags.lru_list.next;
- BUG_ON(tmp == NULL);
- fq = list_entry(tmp, struct nf_ct_frag6_queue, q.lru_list);
- atomic_inc(&fq->q.refcnt);
- read_unlock(&nf_frags.lock);
-
- spin_lock(&fq->q.lock);
- if (!(fq->q.last_in&COMPLETE))
- fq_kill(fq);
- spin_unlock(&fq->q.lock);
-
- fq_put(fq, &work);
- }
+ inet_frag_evictor(&nf_frags);
}
static void nf_ct_frag6_expire(unsigned long data)
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 940b7d2383e..02e4e855b92 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -185,33 +185,11 @@ static __inline__ void fq_kill(struct frag_queue *fq)
static void ip6_evictor(struct inet6_dev *idev)
{
- struct frag_queue *fq;
- struct list_head *tmp;
- int work;
-
- work = atomic_read(&ip6_frags.mem) - ip6_frags_ctl.low_thresh;
- if (work <= 0)
- return;
-
- while(work > 0) {
- read_lock(&ip6_frags.lock);
- if (list_empty(&ip6_frags.lru_list)) {
- read_unlock(&ip6_frags.lock);
- return;
- }
- tmp = ip6_frags.lru_list.next;
- fq = list_entry(tmp, struct frag_queue, q.lru_list);
- atomic_inc(&fq->q.refcnt);
- read_unlock(&ip6_frags.lock);
+ int evicted;
- spin_lock(&fq->q.lock);
- if (!(fq->q.last_in&COMPLETE))
- fq_kill(fq);
- spin_unlock(&fq->q.lock);
-
- fq_put(fq, &work);
- IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS);
- }
+ evicted = inet_frag_evictor(&ip6_frags);
+ if (evicted)
+ IP6_ADD_STATS_BH(idev, IPSTATS_MIB_REASMFAILS, evicted);
}
static void ip6_frag_expire(unsigned long data)