Skip to content

Commit 3ef0eb0

Browse files
netoptimizerdavem330
authored andcommitted
net: frag, move LRU list maintenance outside of rwlock
Updating the fragmentation queues LRU (Least-Recently-Used) list, required taking the hash writer lock. However, the LRU list isn't tied to the hash at all, so we can use a separate lock for it. Original-idea-by: Florian Westphal <[email protected]> Signed-off-by: Jesper Dangaard Brouer <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6d7b857 commit 3ef0eb0

File tree

5 files changed

+33
-14
lines changed

5 files changed

+33
-14
lines changed

include/net/inet_frag.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
struct netns_frags {
77
int nqueues;
88
struct list_head lru_list;
9+
spinlock_t lru_lock;
910

1011
/* The percpu_counter "mem" need to be cacheline aligned.
1112
* mem.count must not share cacheline with other writers
@@ -116,4 +117,25 @@ static inline int sum_frag_mem_limit(struct netns_frags *nf)
116117
return percpu_counter_sum_positive(&nf->mem);
117118
}
118119

120+
static inline void inet_frag_lru_move(struct inet_frag_queue *q)
121+
{
122+
spin_lock(&q->net->lru_lock);
123+
list_move_tail(&q->lru_list, &q->net->lru_list);
124+
spin_unlock(&q->net->lru_lock);
125+
}
126+
127+
static inline void inet_frag_lru_del(struct inet_frag_queue *q)
128+
{
129+
spin_lock(&q->net->lru_lock);
130+
list_del(&q->lru_list);
131+
spin_unlock(&q->net->lru_lock);
132+
}
133+
134+
static inline void inet_frag_lru_add(struct netns_frags *nf,
135+
struct inet_frag_queue *q)
136+
{
137+
spin_lock(&nf->lru_lock);
138+
list_add_tail(&q->lru_list, &nf->lru_list);
139+
spin_unlock(&nf->lru_lock);
140+
}
119141
#endif

net/ipv4/inet_fragment.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ void inet_frags_init_net(struct netns_frags *nf)
7575
nf->nqueues = 0;
7676
init_frag_mem_limit(nf);
7777
INIT_LIST_HEAD(&nf->lru_list);
78+
spin_lock_init(&nf->lru_lock);
7879
}
7980
EXPORT_SYMBOL(inet_frags_init_net);
8081

@@ -100,9 +101,9 @@ static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f)
100101
{
101102
write_lock(&f->lock);
102103
hlist_del(&fq->list);
103-
list_del(&fq->lru_list);
104104
fq->net->nqueues--;
105105
write_unlock(&f->lock);
106+
inet_frag_lru_del(fq);
106107
}
107108

108109
void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f)
@@ -170,16 +171,17 @@ int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force)
170171

171172
work = frag_mem_limit(nf) - nf->low_thresh;
172173
while (work > 0) {
173-
read_lock(&f->lock);
174+
spin_lock(&nf->lru_lock);
175+
174176
if (list_empty(&nf->lru_list)) {
175-
read_unlock(&f->lock);
177+
spin_unlock(&nf->lru_lock);
176178
break;
177179
}
178180

179181
q = list_first_entry(&nf->lru_list,
180182
struct inet_frag_queue, lru_list);
181183
atomic_inc(&q->refcnt);
182-
read_unlock(&f->lock);
184+
spin_unlock(&nf->lru_lock);
183185

184186
spin_lock(&q->lock);
185187
if (!(q->last_in & INET_FRAG_COMPLETE))
@@ -233,9 +235,9 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
233235

234236
atomic_inc(&qp->refcnt);
235237
hlist_add_head(&qp->list, &f->hash[hash]);
236-
list_add_tail(&qp->lru_list, &nf->lru_list);
237238
nf->nqueues++;
238239
write_unlock(&f->lock);
240+
inet_frag_lru_add(nf, qp);
239241
return qp;
240242
}
241243

net/ipv4/ip_fragment.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -529,9 +529,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
529529
qp->q.meat == qp->q.len)
530530
return ip_frag_reasm(qp, prev, dev);
531531

532-
write_lock(&ip4_frags.lock);
533-
list_move_tail(&qp->q.lru_list, &qp->q.net->lru_list);
534-
write_unlock(&ip4_frags.lock);
532+
inet_frag_lru_move(&qp->q);
535533
return -EINPROGRESS;
536534

537535
err:

net/ipv6/netfilter/nf_conntrack_reasm.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,8 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb,
328328
fq->nhoffset = nhoff;
329329
fq->q.last_in |= INET_FRAG_FIRST_IN;
330330
}
331-
write_lock(&nf_frags.lock);
332-
list_move_tail(&fq->q.lru_list, &fq->q.net->lru_list);
333-
write_unlock(&nf_frags.lock);
331+
332+
inet_frag_lru_move(&fq->q);
334333
return 0;
335334

336335
discard_fq:

net/ipv6/reassembly.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,9 +341,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
341341
fq->q.meat == fq->q.len)
342342
return ip6_frag_reasm(fq, prev, dev);
343343

344-
write_lock(&ip6_frags.lock);
345-
list_move_tail(&fq->q.lru_list, &fq->q.net->lru_list);
346-
write_unlock(&ip6_frags.lock);
344+
inet_frag_lru_move(&fq->q);
347345
return -1;
348346

349347
discard_fq:

0 commit comments

Comments
 (0)