Skip to content

Commit d63382a

Browse files
q2venkuba-moo
authored andcommitted
neighbour: Annotate neigh_table.phash_buckets and pneigh_entry.next with __rcu.
The next patch will free pneigh_entry with call_rcu(). Then, we need to annotate neigh_table.phash_buckets[] and pneigh_entry.next with __rcu. To make the next patch cleaner, let's annotate the fields in advance. Currently, all accesses to the fields are under the neigh table lock, so rcu_dereference_protected() is used with 1 for now, but most of them (except in pneigh_delete() and pneigh_ifdown_and_unlock()) will be replaced with rcu_dereference() and rcu_dereference_check(). Note that pneigh_ifdown_and_unlock() changes pneigh_entry.next to a local list, which is illegal because the RCU iterator could be moved to another list. This part will be fixed in the next patch. Signed-off-by: Kuniyuki Iwashima <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent e804bd8 commit d63382a

File tree

2 files changed

+33
-23
lines changed

2 files changed

+33
-23
lines changed

include/net/neighbour.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ struct neigh_ops {
176176
};
177177

178178
struct pneigh_entry {
179-
struct pneigh_entry *next;
179+
struct pneigh_entry __rcu *next;
180180
possible_net_t net;
181181
struct net_device *dev;
182182
netdevice_tracker dev_tracker;
@@ -236,7 +236,7 @@ struct neigh_table {
236236
unsigned long last_rand;
237237
struct neigh_statistics __percpu *stats;
238238
struct neigh_hash_table __rcu *nht;
239-
struct pneigh_entry **phash_buckets;
239+
struct pneigh_entry __rcu **phash_buckets;
240240
};
241241

242242
static inline int neigh_parms_family(struct neigh_parms *p)

net/core/neighbour.c

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,8 @@ static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
731731
net_eq(pneigh_net(n), net) &&
732732
(n->dev == dev || !n->dev))
733733
return n;
734-
n = n->next;
734+
735+
n = rcu_dereference_protected(n->next, 1);
735736
}
736737
return NULL;
737738
}
@@ -742,7 +743,7 @@ struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
742743
unsigned int key_len = tbl->key_len;
743744
u32 hash_val = pneigh_hash(pkey, key_len);
744745

745-
return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
746+
return __pneigh_lookup_1(rcu_dereference_protected(tbl->phash_buckets[hash_val], 1),
746747
net, pkey, key_len, dev);
747748
}
748749
EXPORT_SYMBOL_GPL(__pneigh_lookup);
@@ -759,7 +760,7 @@ struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl,
759760
hash_val = pneigh_hash(pkey, key_len);
760761

761762
read_lock_bh(&tbl->lock);
762-
n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
763+
n = __pneigh_lookup_1(rcu_dereference_protected(tbl->phash_buckets[hash_val], 1),
763764
net, pkey, key_len, dev);
764765
read_unlock_bh(&tbl->lock);
765766

@@ -778,7 +779,7 @@ struct pneigh_entry *pneigh_create(struct neigh_table *tbl,
778779
ASSERT_RTNL();
779780

780781
read_lock_bh(&tbl->lock);
781-
n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
782+
n = __pneigh_lookup_1(rcu_dereference_protected(tbl->phash_buckets[hash_val], 1),
782783
net, pkey, key_len, dev);
783784
read_unlock_bh(&tbl->lock);
784785

@@ -803,7 +804,7 @@ struct pneigh_entry *pneigh_create(struct neigh_table *tbl,
803804

804805
write_lock_bh(&tbl->lock);
805806
n->next = tbl->phash_buckets[hash_val];
806-
tbl->phash_buckets[hash_val] = n;
807+
rcu_assign_pointer(tbl->phash_buckets[hash_val], n);
807808
write_unlock_bh(&tbl->lock);
808809
out:
809810
return n;
@@ -812,16 +813,20 @@ struct pneigh_entry *pneigh_create(struct neigh_table *tbl,
812813
int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
813814
struct net_device *dev)
814815
{
815-
struct pneigh_entry *n, **np;
816-
unsigned int key_len = tbl->key_len;
817-
u32 hash_val = pneigh_hash(pkey, key_len);
816+
struct pneigh_entry *n, __rcu **np;
817+
unsigned int key_len;
818+
u32 hash_val;
819+
820+
key_len = tbl->key_len;
821+
hash_val = pneigh_hash(pkey, key_len);
818822

819823
write_lock_bh(&tbl->lock);
820-
for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
824+
for (np = &tbl->phash_buckets[hash_val];
825+
(n = rcu_dereference_protected(*np, 1)) != NULL;
821826
np = &n->next) {
822827
if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
823828
net_eq(pneigh_net(n), net)) {
824-
*np = n->next;
829+
rcu_assign_pointer(*np, n->next);
825830
write_unlock_bh(&tbl->lock);
826831
if (tbl->pdestructor)
827832
tbl->pdestructor(n);
@@ -838,17 +843,17 @@ static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
838843
struct net_device *dev,
839844
bool skip_perm)
840845
{
841-
struct pneigh_entry *n, **np, *freelist = NULL;
846+
struct pneigh_entry *n, __rcu **np, *freelist = NULL;
842847
u32 h;
843848

844849
for (h = 0; h <= PNEIGH_HASHMASK; h++) {
845850
np = &tbl->phash_buckets[h];
846-
while ((n = *np) != NULL) {
851+
while ((n = rcu_dereference_protected(*np, 1)) != NULL) {
847852
if (skip_perm && n->permanent)
848853
goto skip;
849854
if (!dev || n->dev == dev) {
850-
*np = n->next;
851-
n->next = freelist;
855+
rcu_assign_pointer(*np, n->next);
856+
rcu_assign_pointer(n->next, freelist);
852857
freelist = n;
853858
continue;
854859
}
@@ -858,7 +863,7 @@ static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
858863
}
859864
write_unlock_bh(&tbl->lock);
860865
while ((n = freelist)) {
861-
freelist = n->next;
866+
freelist = rcu_dereference_protected(n->next, 1);
862867
n->next = NULL;
863868
if (tbl->pdestructor)
864869
tbl->pdestructor(n);
@@ -2794,7 +2799,9 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
27942799
for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
27952800
if (h > s_h)
27962801
s_idx = 0;
2797-
for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
2802+
for (n = rcu_dereference_protected(tbl->phash_buckets[h], 1), idx = 0;
2803+
n;
2804+
n = rcu_dereference_protected(n->next, 1)) {
27982805
if (idx < s_idx || pneigh_net(n) != net)
27992806
goto next;
28002807
if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
@@ -3288,9 +3295,10 @@ static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
32883295

32893296
state->flags |= NEIGH_SEQ_IS_PNEIGH;
32903297
for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
3291-
pn = tbl->phash_buckets[bucket];
3298+
pn = rcu_dereference_protected(tbl->phash_buckets[bucket], 1);
3299+
32923300
while (pn && !net_eq(pneigh_net(pn), net))
3293-
pn = pn->next;
3301+
pn = rcu_dereference_protected(pn->next, 1);
32943302
if (pn)
32953303
break;
32963304
}
@@ -3308,15 +3316,17 @@ static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
33083316
struct neigh_table *tbl = state->tbl;
33093317

33103318
do {
3311-
pn = pn->next;
3319+
pn = rcu_dereference_protected(pn->next, 1);
33123320
} while (pn && !net_eq(pneigh_net(pn), net));
33133321

33143322
while (!pn) {
33153323
if (++state->bucket > PNEIGH_HASHMASK)
33163324
break;
3317-
pn = tbl->phash_buckets[state->bucket];
3325+
3326+
pn = rcu_dereference_protected(tbl->phash_buckets[state->bucket], 1);
3327+
33183328
while (pn && !net_eq(pneigh_net(pn), net))
3319-
pn = pn->next;
3329+
pn = rcu_dereference_protected(pn->next, 1);
33203330
if (pn)
33213331
break;
33223332
}

0 commit comments

Comments
 (0)