diff options
Diffstat (limited to 'net/ipv4/inet_fragment.c')
| -rw-r--r-- | net/ipv4/inet_fragment.c | 40 |
1 files changed, 15 insertions, 25 deletions
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 5e346a082e5f..d0a7c0319e3d 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c | |||
| @@ -131,34 +131,22 @@ inet_evict_bucket(struct inet_frags *f, struct inet_frag_bucket *hb) | |||
| 131 | unsigned int evicted = 0; | 131 | unsigned int evicted = 0; |
| 132 | HLIST_HEAD(expired); | 132 | HLIST_HEAD(expired); |
| 133 | 133 | ||
| 134 | evict_again: | ||
| 135 | spin_lock(&hb->chain_lock); | 134 | spin_lock(&hb->chain_lock); |
| 136 | 135 | ||
| 137 | hlist_for_each_entry_safe(fq, n, &hb->chain, list) { | 136 | hlist_for_each_entry_safe(fq, n, &hb->chain, list) { |
| 138 | if (!inet_fragq_should_evict(fq)) | 137 | if (!inet_fragq_should_evict(fq)) |
| 139 | continue; | 138 | continue; |
| 140 | 139 | ||
| 141 | if (!del_timer(&fq->timer)) { | 140 | if (!del_timer(&fq->timer)) |
| 142 | /* q expiring right now thus increment its refcount so | 141 | continue; |
| 143 | * it won't be freed under us and wait until the timer | ||
| 144 | * has finished executing then destroy it | ||
| 145 | */ | ||
| 146 | atomic_inc(&fq->refcnt); | ||
| 147 | spin_unlock(&hb->chain_lock); | ||
| 148 | del_timer_sync(&fq->timer); | ||
| 149 | inet_frag_put(fq, f); | ||
| 150 | goto evict_again; | ||
| 151 | } | ||
| 152 | 142 | ||
| 153 | fq->flags |= INET_FRAG_EVICTED; | 143 | hlist_add_head(&fq->list_evictor, &expired); |
| 154 | hlist_del(&fq->list); | ||
| 155 | hlist_add_head(&fq->list, &expired); | ||
| 156 | ++evicted; | 144 | ++evicted; |
| 157 | } | 145 | } |
| 158 | 146 | ||
| 159 | spin_unlock(&hb->chain_lock); | 147 | spin_unlock(&hb->chain_lock); |
| 160 | 148 | ||
| 161 | hlist_for_each_entry_safe(fq, n, &expired, list) | 149 | hlist_for_each_entry_safe(fq, n, &expired, list_evictor) |
| 162 | f->frag_expire((unsigned long) fq); | 150 | f->frag_expire((unsigned long) fq); |
| 163 | 151 | ||
| 164 | return evicted; | 152 | return evicted; |
| @@ -240,18 +228,20 @@ void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f) | |||
| 240 | int i; | 228 | int i; |
| 241 | 229 | ||
| 242 | nf->low_thresh = 0; | 230 | nf->low_thresh = 0; |
| 243 | local_bh_disable(); | ||
| 244 | 231 | ||
| 245 | evict_again: | 232 | evict_again: |
| 233 | local_bh_disable(); | ||
| 246 | seq = read_seqbegin(&f->rnd_seqlock); | 234 | seq = read_seqbegin(&f->rnd_seqlock); |
| 247 | 235 | ||
| 248 | for (i = 0; i < INETFRAGS_HASHSZ ; i++) | 236 | for (i = 0; i < INETFRAGS_HASHSZ ; i++) |
| 249 | inet_evict_bucket(f, &f->hash[i]); | 237 | inet_evict_bucket(f, &f->hash[i]); |
| 250 | 238 | ||
| 251 | if (read_seqretry(&f->rnd_seqlock, seq)) | ||
| 252 | goto evict_again; | ||
| 253 | |||
| 254 | local_bh_enable(); | 239 | local_bh_enable(); |
| 240 | cond_resched(); | ||
| 241 | |||
| 242 | if (read_seqretry(&f->rnd_seqlock, seq) || | ||
| 243 | percpu_counter_sum(&nf->mem)) | ||
| 244 | goto evict_again; | ||
| 255 | 245 | ||
| 256 | percpu_counter_destroy(&nf->mem); | 246 | percpu_counter_destroy(&nf->mem); |
| 257 | } | 247 | } |
| @@ -284,8 +274,8 @@ static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f) | |||
| 284 | struct inet_frag_bucket *hb; | 274 | struct inet_frag_bucket *hb; |
| 285 | 275 | ||
| 286 | hb = get_frag_bucket_locked(fq, f); | 276 | hb = get_frag_bucket_locked(fq, f); |
| 287 | if (!(fq->flags & INET_FRAG_EVICTED)) | 277 | hlist_del(&fq->list); |
| 288 | hlist_del(&fq->list); | 278 | fq->flags |= INET_FRAG_COMPLETE; |
| 289 | spin_unlock(&hb->chain_lock); | 279 | spin_unlock(&hb->chain_lock); |
| 290 | } | 280 | } |
| 291 | 281 | ||
| @@ -297,7 +287,6 @@ void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f) | |||
| 297 | if (!(fq->flags & INET_FRAG_COMPLETE)) { | 287 | if (!(fq->flags & INET_FRAG_COMPLETE)) { |
| 298 | fq_unlink(fq, f); | 288 | fq_unlink(fq, f); |
| 299 | atomic_dec(&fq->refcnt); | 289 | atomic_dec(&fq->refcnt); |
| 300 | fq->flags |= INET_FRAG_COMPLETE; | ||
| 301 | } | 290 | } |
| 302 | } | 291 | } |
| 303 | EXPORT_SYMBOL(inet_frag_kill); | 292 | EXPORT_SYMBOL(inet_frag_kill); |
| @@ -330,11 +319,12 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f) | |||
| 330 | fp = xp; | 319 | fp = xp; |
| 331 | } | 320 | } |
| 332 | sum = sum_truesize + f->qsize; | 321 | sum = sum_truesize + f->qsize; |
| 333 | sub_frag_mem_limit(q, sum); | ||
| 334 | 322 | ||
| 335 | if (f->destructor) | 323 | if (f->destructor) |
| 336 | f->destructor(q); | 324 | f->destructor(q); |
| 337 | kmem_cache_free(f->frags_cachep, q); | 325 | kmem_cache_free(f->frags_cachep, q); |
| 326 | |||
| 327 | sub_frag_mem_limit(nf, sum); | ||
| 338 | } | 328 | } |
| 339 | EXPORT_SYMBOL(inet_frag_destroy); | 329 | EXPORT_SYMBOL(inet_frag_destroy); |
| 340 | 330 | ||
| @@ -390,7 +380,7 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, | |||
| 390 | 380 | ||
| 391 | q->net = nf; | 381 | q->net = nf; |
| 392 | f->constructor(q, arg); | 382 | f->constructor(q, arg); |
| 393 | add_frag_mem_limit(q, f->qsize); | 383 | add_frag_mem_limit(nf, f->qsize); |
| 394 | 384 | ||
| 395 | setup_timer(&q->timer, f->frag_expire, (unsigned long)q); | 385 | setup_timer(&q->timer, f->frag_expire, (unsigned long)q); |
| 396 | spin_lock_init(&q->lock); | 386 | spin_lock_init(&q->lock); |
