aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/ip_fragment.c40
-rw-r--r--net/ipv6/reassembly.c41
2 files changed, 30 insertions, 51 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index e7d26d9943c2..8ce0ce2ee48e 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -71,7 +71,7 @@ struct ipfrag_skb_cb
71 71
72/* Describe an entry in the "incomplete datagrams" queue. */ 72/* Describe an entry in the "incomplete datagrams" queue. */
73struct ipq { 73struct ipq {
74 struct ipq *next; /* linked list pointers */ 74 struct hlist_node list;
75 struct list_head lru_list; /* lru list member */ 75 struct list_head lru_list; /* lru list member */
76 u32 user; 76 u32 user;
77 u32 saddr; 77 u32 saddr;
@@ -89,7 +89,6 @@ struct ipq {
89 spinlock_t lock; 89 spinlock_t lock;
90 atomic_t refcnt; 90 atomic_t refcnt;
91 struct timer_list timer; /* when will this queue expire? */ 91 struct timer_list timer; /* when will this queue expire? */
92 struct ipq **pprev;
93 int iif; 92 int iif;
94 struct timeval stamp; 93 struct timeval stamp;
95}; 94};
@@ -99,7 +98,7 @@ struct ipq {
99#define IPQ_HASHSZ 64 98#define IPQ_HASHSZ 64
100 99
101/* Per-bucket lock is easy to add now. */ 100/* Per-bucket lock is easy to add now. */
102static struct ipq *ipq_hash[IPQ_HASHSZ]; 101static struct hlist_head ipq_hash[IPQ_HASHSZ];
103static DEFINE_RWLOCK(ipfrag_lock); 102static DEFINE_RWLOCK(ipfrag_lock);
104static u32 ipfrag_hash_rnd; 103static u32 ipfrag_hash_rnd;
105static LIST_HEAD(ipq_lru_list); 104static LIST_HEAD(ipq_lru_list);
@@ -107,9 +106,7 @@ int ip_frag_nqueues = 0;
107 106
108static __inline__ void __ipq_unlink(struct ipq *qp) 107static __inline__ void __ipq_unlink(struct ipq *qp)
109{ 108{
110 if(qp->next) 109 hlist_del(&qp->list);
111 qp->next->pprev = qp->pprev;
112 *qp->pprev = qp->next;
113 list_del(&qp->lru_list); 110 list_del(&qp->lru_list);
114 ip_frag_nqueues--; 111 ip_frag_nqueues--;
115} 112}
@@ -139,27 +136,18 @@ static void ipfrag_secret_rebuild(unsigned long dummy)
139 get_random_bytes(&ipfrag_hash_rnd, sizeof(u32)); 136 get_random_bytes(&ipfrag_hash_rnd, sizeof(u32));
140 for (i = 0; i < IPQ_HASHSZ; i++) { 137 for (i = 0; i < IPQ_HASHSZ; i++) {
141 struct ipq *q; 138 struct ipq *q;
139 struct hlist_node *p, *n;
142 140
143 q = ipq_hash[i]; 141 hlist_for_each_entry_safe(q, p, n, &ipq_hash[i], list) {
144 while (q) {
145 struct ipq *next = q->next;
146 unsigned int hval = ipqhashfn(q->id, q->saddr, 142 unsigned int hval = ipqhashfn(q->id, q->saddr,
147 q->daddr, q->protocol); 143 q->daddr, q->protocol);
148 144
149 if (hval != i) { 145 if (hval != i) {
150 /* Unlink. */ 146 hlist_del(&q->list);
151 if (q->next)
152 q->next->pprev = q->pprev;
153 *q->pprev = q->next;
154 147
155 /* Relink to new hash chain. */ 148 /* Relink to new hash chain. */
156 if ((q->next = ipq_hash[hval]) != NULL) 149 hlist_add_head(&q->list, &ipq_hash[hval]);
157 q->next->pprev = &q->next;
158 ipq_hash[hval] = q;
159 q->pprev = &ipq_hash[hval];
160 } 150 }
161
162 q = next;
163 } 151 }
164 } 152 }
165 write_unlock(&ipfrag_lock); 153 write_unlock(&ipfrag_lock);
@@ -310,14 +298,16 @@ out:
310static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in) 298static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in)
311{ 299{
312 struct ipq *qp; 300 struct ipq *qp;
313 301#ifdef CONFIG_SMP
302 struct hlist_node *n;
303#endif
314 write_lock(&ipfrag_lock); 304 write_lock(&ipfrag_lock);
315#ifdef CONFIG_SMP 305#ifdef CONFIG_SMP
316 /* With SMP race we have to recheck hash table, because 306 /* With SMP race we have to recheck hash table, because
317 * such entry could be created on other cpu, while we 307 * such entry could be created on other cpu, while we
318 * promoted read lock to write lock. 308 * promoted read lock to write lock.
319 */ 309 */
320 for(qp = ipq_hash[hash]; qp; qp = qp->next) { 310 hlist_for_each_entry(qp, n, &ipq_hash[hash], list) {
321 if(qp->id == qp_in->id && 311 if(qp->id == qp_in->id &&
322 qp->saddr == qp_in->saddr && 312 qp->saddr == qp_in->saddr &&
323 qp->daddr == qp_in->daddr && 313 qp->daddr == qp_in->daddr &&
@@ -337,10 +327,7 @@ static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in)
337 atomic_inc(&qp->refcnt); 327 atomic_inc(&qp->refcnt);
338 328
339 atomic_inc(&qp->refcnt); 329 atomic_inc(&qp->refcnt);
340 if((qp->next = ipq_hash[hash]) != NULL) 330 hlist_add_head(&qp->list, &ipq_hash[hash]);
341 qp->next->pprev = &qp->next;
342 ipq_hash[hash] = qp;
343 qp->pprev = &ipq_hash[hash];
344 INIT_LIST_HEAD(&qp->lru_list); 331 INIT_LIST_HEAD(&qp->lru_list);
345 list_add_tail(&qp->lru_list, &ipq_lru_list); 332 list_add_tail(&qp->lru_list, &ipq_lru_list);
346 ip_frag_nqueues++; 333 ip_frag_nqueues++;
@@ -392,9 +379,10 @@ static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
392 __u8 protocol = iph->protocol; 379 __u8 protocol = iph->protocol;
393 unsigned int hash = ipqhashfn(id, saddr, daddr, protocol); 380 unsigned int hash = ipqhashfn(id, saddr, daddr, protocol);
394 struct ipq *qp; 381 struct ipq *qp;
382 struct hlist_node *n;
395 383
396 read_lock(&ipfrag_lock); 384 read_lock(&ipfrag_lock);
397 for(qp = ipq_hash[hash]; qp; qp = qp->next) { 385 hlist_for_each_entry(qp, n, &ipq_hash[hash], list) {
398 if(qp->id == id && 386 if(qp->id == id &&
399 qp->saddr == saddr && 387 qp->saddr == saddr &&
400 qp->daddr == daddr && 388 qp->daddr == daddr &&
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index e4fe9ee484dd..5d316cb72ec9 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -74,7 +74,7 @@ struct ip6frag_skb_cb
74 74
75struct frag_queue 75struct frag_queue
76{ 76{
77 struct frag_queue *next; 77 struct hlist_node list;
78 struct list_head lru_list; /* lru list member */ 78 struct list_head lru_list; /* lru list member */
79 79
80 __u32 id; /* fragment id */ 80 __u32 id; /* fragment id */
@@ -95,14 +95,13 @@ struct frag_queue
95#define FIRST_IN 2 95#define FIRST_IN 2
96#define LAST_IN 1 96#define LAST_IN 1
97 __u16 nhoffset; 97 __u16 nhoffset;
98 struct frag_queue **pprev;
99}; 98};
100 99
101/* Hash table. */ 100/* Hash table. */
102 101
103#define IP6Q_HASHSZ 64 102#define IP6Q_HASHSZ 64
104 103
105static struct frag_queue *ip6_frag_hash[IP6Q_HASHSZ]; 104static struct hlist_head ip6_frag_hash[IP6Q_HASHSZ];
106static DEFINE_RWLOCK(ip6_frag_lock); 105static DEFINE_RWLOCK(ip6_frag_lock);
107static u32 ip6_frag_hash_rnd; 106static u32 ip6_frag_hash_rnd;
108static LIST_HEAD(ip6_frag_lru_list); 107static LIST_HEAD(ip6_frag_lru_list);
@@ -110,9 +109,7 @@ int ip6_frag_nqueues = 0;
110 109
111static __inline__ void __fq_unlink(struct frag_queue *fq) 110static __inline__ void __fq_unlink(struct frag_queue *fq)
112{ 111{
113 if(fq->next) 112 hlist_del(&fq->list);
114 fq->next->pprev = fq->pprev;
115 *fq->pprev = fq->next;
116 list_del(&fq->lru_list); 113 list_del(&fq->lru_list);
117 ip6_frag_nqueues--; 114 ip6_frag_nqueues--;
118} 115}
@@ -163,28 +160,21 @@ static void ip6_frag_secret_rebuild(unsigned long dummy)
163 get_random_bytes(&ip6_frag_hash_rnd, sizeof(u32)); 160 get_random_bytes(&ip6_frag_hash_rnd, sizeof(u32));
164 for (i = 0; i < IP6Q_HASHSZ; i++) { 161 for (i = 0; i < IP6Q_HASHSZ; i++) {
165 struct frag_queue *q; 162 struct frag_queue *q;
163 struct hlist_node *p, *n;
166 164
167 q = ip6_frag_hash[i]; 165 hlist_for_each_entry_safe(q, p, n, &ip6_frag_hash[i], list) {
168 while (q) {
169 struct frag_queue *next = q->next;
170 unsigned int hval = ip6qhashfn(q->id, 166 unsigned int hval = ip6qhashfn(q->id,
171 &q->saddr, 167 &q->saddr,
172 &q->daddr); 168 &q->daddr);
173 169
174 if (hval != i) { 170 if (hval != i) {
175 /* Unlink. */ 171 hlist_del(&q->list);
176 if (q->next)
177 q->next->pprev = q->pprev;
178 *q->pprev = q->next;
179 172
180 /* Relink to new hash chain. */ 173 /* Relink to new hash chain. */
181 if ((q->next = ip6_frag_hash[hval]) != NULL) 174 hlist_add_head(&q->list,
182 q->next->pprev = &q->next; 175 &ip6_frag_hash[hval]);
183 ip6_frag_hash[hval] = q;
184 q->pprev = &ip6_frag_hash[hval];
185 }
186 176
187 q = next; 177 }
188 } 178 }
189 } 179 }
190 write_unlock(&ip6_frag_lock); 180 write_unlock(&ip6_frag_lock);
@@ -337,10 +327,13 @@ static struct frag_queue *ip6_frag_intern(unsigned int hash,
337 struct frag_queue *fq_in) 327 struct frag_queue *fq_in)
338{ 328{
339 struct frag_queue *fq; 329 struct frag_queue *fq;
330#ifdef CONFIG_SMP
331 struct hlist_node *n;
332#endif
340 333
341 write_lock(&ip6_frag_lock); 334 write_lock(&ip6_frag_lock);
342#ifdef CONFIG_SMP 335#ifdef CONFIG_SMP
343 for (fq = ip6_frag_hash[hash]; fq; fq = fq->next) { 336 hlist_for_each_entry(fq, n, &ip6_frag_hash[hash], list) {
344 if (fq->id == fq_in->id && 337 if (fq->id == fq_in->id &&
345 ipv6_addr_equal(&fq_in->saddr, &fq->saddr) && 338 ipv6_addr_equal(&fq_in->saddr, &fq->saddr) &&
346 ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) { 339 ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) {
@@ -358,10 +351,7 @@ static struct frag_queue *ip6_frag_intern(unsigned int hash,
358 atomic_inc(&fq->refcnt); 351 atomic_inc(&fq->refcnt);
359 352
360 atomic_inc(&fq->refcnt); 353 atomic_inc(&fq->refcnt);
361 if((fq->next = ip6_frag_hash[hash]) != NULL) 354 hlist_add_head(&fq->list, &ip6_frag_hash[hash]);
362 fq->next->pprev = &fq->next;
363 ip6_frag_hash[hash] = fq;
364 fq->pprev = &ip6_frag_hash[hash];
365 INIT_LIST_HEAD(&fq->lru_list); 355 INIT_LIST_HEAD(&fq->lru_list);
366 list_add_tail(&fq->lru_list, &ip6_frag_lru_list); 356 list_add_tail(&fq->lru_list, &ip6_frag_lru_list);
367 ip6_frag_nqueues++; 357 ip6_frag_nqueues++;
@@ -401,10 +391,11 @@ static __inline__ struct frag_queue *
401fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst) 391fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst)
402{ 392{
403 struct frag_queue *fq; 393 struct frag_queue *fq;
394 struct hlist_node *n;
404 unsigned int hash = ip6qhashfn(id, src, dst); 395 unsigned int hash = ip6qhashfn(id, src, dst);
405 396
406 read_lock(&ip6_frag_lock); 397 read_lock(&ip6_frag_lock);
407 for(fq = ip6_frag_hash[hash]; fq; fq = fq->next) { 398 hlist_for_each_entry(fq, n, &ip6_frag_hash[hash], list) {
408 if (fq->id == id && 399 if (fq->id == id &&
409 ipv6_addr_equal(src, &fq->saddr) && 400 ipv6_addr_equal(src, &fq->saddr) &&
410 ipv6_addr_equal(dst, &fq->daddr)) { 401 ipv6_addr_equal(dst, &fq->daddr)) {