to rx frag either legal or illegal.
--- linux-2.6.22.1/net/ipv4/ip_fragment.c 2007-07-11 02:56:30.000000000 +0800
+++ /usr/src/chg/ip_fragment3.c 2007-08-21 11:27:03.000000000 +0800
@@ -25,6 +25,7 @@
#include <linux/compiler.h>
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/rcupdate.h>
#include <linux/mm.h>
#include <linux/jiffies.h>
#include <linux/skbuff.h>
@@ -111,8 +112,8 @@ int ip_frag_nqueues = 0;
static __inline__ void __ipq_unlink(struct ipq *qp)
{
- hlist_del(&qp->list);
- list_del(&qp->lru_list);
+ hlist_del_rcu(&qp->list);
+ list_del_rcu(&qp->lru_list);
ip_frag_nqueues--;
}
@@ -149,10 +150,10 @@ static void ipfrag_secret_rebuild(unsign
q->daddr, q->protocol);
if (hval != i) {
- hlist_del(&q->list);
+ hlist_del_rcu(&q->list);
/* Relink to new hash chain. */
- hlist_add_head(&q->list, &ipq_hash[hval]);
+ hlist_add_head_rcu(&q->list, &ipq_hash[hval]);
}
}
}
@@ -252,16 +253,16 @@ static void ip_evictor(void)
return;
while (work > 0) {
- read_lock(&ipfrag_lock);
+ rcu_read_lock();
if (list_empty(&ipq_lru_list)) {
- read_unlock(&ipfrag_lock);
+ rcu_read_unlock();
return;
}
- tmp = ipq_lru_list.next;
- qp = list_entry(tmp, struct ipq, lru_list);
+ tmp = rcu_dereference(ipq_lru_list.next);
+ qp = list_entry(tmp, struct ipq, lru_list);
atomic_inc(&qp->refcnt);
- read_unlock(&ipfrag_lock);
-
+ rcu_read_unlock();
+
spin_lock(&qp->lock);
if (!(qp->last_in&COMPLETE))
ipq_kill(qp);
@@ -320,7 +321,7 @@ static struct ipq *ip_frag_intern(struct
* such entry could be created on other cpu, while we
* promoted read lock to write lock.
*/
- hlist_for_each_entry(qp, n, &ipq_hash[hash], list) {
+ hlist_for_each_entry_rcu(qp, n, &ipq_hash[hash], list) {
if (qp->id == qp_in->id &&
qp->saddr == qp_in->saddr &&
qp->daddr == qp_in->daddr &&
@@ -340,9 +341,9 @@ static struct ipq *ip_frag_intern(struct
atomic_inc(&qp->refcnt);
atomic_inc(&qp->refcnt);
- hlist_add_head(&qp->list, &ipq_hash[hash]);
+ hlist_add_head_rcu(&qp->list, &ipq_hash[hash]);
INIT_LIST_HEAD(&qp->lru_list);
- list_add_tail(&qp->lru_list, &ipq_lru_list);
+ list_add_tail_rcu(&qp->lru_list, &ipq_lru_list);
ip_frag_nqueues++;
write_unlock(&ipfrag_lock);
return qp;
@@ -395,20 +396,20 @@ static inline struct ipq *ip_find(struct
struct ipq *qp;
struct hlist_node *n;
- read_lock(&ipfrag_lock);
+ rcu_read_lock();
hash = ipqhashfn(id, saddr, daddr, protocol);
- hlist_for_each_entry(qp, n, &ipq_hash[hash], list) {
+ hlist_for_each_entry_rcu(qp, n, &ipq_hash[hash], list) {
if (qp->id == id &&
qp->saddr == saddr &&
qp->daddr == daddr &&
qp->protocol == protocol &&
qp->user == user) {
atomic_inc(&qp->refcnt);
- read_unlock(&ipfrag_lock);
+ rcu_read_unlock();
return qp;
}
}
- read_unlock(&ipfrag_lock);
+ rcu_read_lock();
return ip_frag_create(iph, user);
}
@@ -599,7 +600,8 @@ static void ip_frag_queue(struct ipq *qp
qp->last_in |= FIRST_IN;
write_lock(&ipfrag_lock);
- list_move_tail(&qp->lru_list, &ipq_lru_list);
+ list_del_rcu(&qp->lru_list);
+ list_add_tail_rcu(&qp->lru_list, &ipq_lru_list);
write_unlock(&ipfrag_lock);
return;