Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

neighbour: Annotate access to neigh_parms fields.

NEIGH_VAR() is read locklessly in the fast path, and IPv6 ndisc uses
NEIGH_VAR_SET() locklessly.

The next patch will convert neightbl_dump_info() to RCU.

Let's annotate accesses to neigh_param with READ_ONCE() and WRITE_ONCE().

Note that ndisc_ifinfo_sysctl_change() uses &NEIGH_VAR() and we cannot
use '&' with READ_ONCE(), so NEIGH_VAR_PTR() is introduced.

Note also that NEIGH_VAR_INIT() does not need WRITE_ONCE() as it is before
parms is published. Also, the only user hippi_neigh_setup_dev() is no
longer called since commit e3804cbebb67 ("net: remove COMPAT_NET_DEV_OPS"),
which looks wrong, but probably no one uses HIPPI and RoadRunner.

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20251022054004.2514876-3-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Kuniyuki Iwashima and committed by
Jakub Kicinski
35d7c708 06d63222

+22 -18
+12 -3
include/net/neighbour.h
··· 92 92 static inline void neigh_var_set(struct neigh_parms *p, int index, int val) 93 93 { 94 94 set_bit(index, p->data_state); 95 - p->data[index] = val; 95 + WRITE_ONCE(p->data[index], val); 96 96 } 97 97 98 - #define NEIGH_VAR(p, attr) ((p)->data[NEIGH_VAR_ ## attr]) 98 + #define __NEIGH_VAR(p, attr) ((p)->data[NEIGH_VAR_ ## attr]) 99 + #define NEIGH_VAR(p, attr) READ_ONCE(__NEIGH_VAR(p, attr)) 100 + #define NEIGH_VAR_PTR(p, attr) (&(__NEIGH_VAR(p, attr))) 99 101 100 102 /* In ndo_neigh_setup, NEIGH_VAR_INIT should be used. 101 103 * In other cases, NEIGH_VAR_SET should be used. 102 104 */ 103 - #define NEIGH_VAR_INIT(p, attr, val) (NEIGH_VAR(p, attr) = val) 105 + #define NEIGH_VAR_INIT(p, attr, val) (__NEIGH_VAR(p, attr) = val) 104 106 #define NEIGH_VAR_SET(p, attr, val) neigh_var_set(p, NEIGH_VAR_ ## attr, val) 105 107 106 108 static inline void neigh_parms_data_state_setall(struct neigh_parms *p) ··· 379 377 } 380 378 381 379 unsigned long neigh_rand_reach_time(unsigned long base); 380 + 381 + static inline void neigh_set_reach_time(struct neigh_parms *p) 382 + { 383 + unsigned long base = NEIGH_VAR(p, BASE_REACHABLE_TIME); 384 + 385 + WRITE_ONCE(p->reachable_time, neigh_rand_reach_time(base)); 386 + } 382 387 383 388 void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, 384 389 struct sk_buff *skb);
+6 -11
net/core/neighbour.c
··· 995 995 996 996 WRITE_ONCE(tbl->last_rand, jiffies); 997 997 list_for_each_entry(p, &tbl->parms_list, list) 998 - p->reachable_time = 999 - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); 998 + neigh_set_reach_time(p); 1000 999 } 1001 1000 1002 1001 if (atomic_read(&tbl->entries) < READ_ONCE(tbl->gc_thresh1)) ··· 1748 1749 if (p) { 1749 1750 p->tbl = tbl; 1750 1751 refcount_set(&p->refcnt, 1); 1751 - p->reachable_time = 1752 - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); 1752 + neigh_set_reach_time(p); 1753 1753 p->qlen = 0; 1754 1754 netdev_hold(dev, &p->dev_tracker, GFP_KERNEL); 1755 1755 p->dev = dev; ··· 1808 1810 list_add(&tbl->parms.list, &tbl->parms_list); 1809 1811 write_pnet(&tbl->parms.net, &init_net); 1810 1812 refcount_set(&tbl->parms.refcnt, 1); 1811 - tbl->parms.reachable_time = 1812 - neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME)); 1813 + neigh_set_reach_time(&tbl->parms); 1813 1814 tbl->parms.qlen = 0; 1814 1815 1815 1816 tbl->stats = alloc_percpu(struct neigh_statistics); ··· 2191 2194 NEIGH_VAR(parms, MCAST_PROBES)) || 2192 2195 nla_put_u32(skb, NDTPA_MCAST_REPROBES, 2193 2196 NEIGH_VAR(parms, MCAST_REPROBES)) || 2194 - nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time, 2197 + nla_put_msecs(skb, NDTPA_REACHABLE_TIME, READ_ONCE(parms->reachable_time), 2195 2198 NDTPA_PAD) || 2196 2199 nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME, 2197 2200 NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) || ··· 2472 2475 * only be effective after the next time neigh_periodic_work 2473 2476 * decides to recompute it (can be multiple minutes) 2474 2477 */ 2475 - p->reachable_time = 2476 - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); 2478 + neigh_set_reach_time(p); 2477 2479 break; 2478 2480 case NDTPA_GC_STALETIME: 2479 2481 NEIGH_VAR_SET(p, GC_STALETIME, ··· 3717 3721 * only be effective after the next time neigh_periodic_work 3718 3722 * decides to recompute it 3719 3723 */ 3720 - p->reachable_time = 3721 - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); 3724 + neigh_set_reach_time(p); 3722 3725 } 3723 3726 return ret; 3724 3727 }
+4 -4
net/ipv6/ndisc.c
··· 1449 1449 BASE_REACHABLE_TIME, rtime); 1450 1450 NEIGH_VAR_SET(in6_dev->nd_parms, 1451 1451 GC_STALETIME, 3 * rtime); 1452 - in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime); 1452 + neigh_set_reach_time(in6_dev->nd_parms); 1453 1453 in6_dev->tstamp = jiffies; 1454 1454 send_ifinfo_notify = true; 1455 1455 } ··· 1948 1948 ret = -1; 1949 1949 1950 1950 if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) { 1951 - if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)) 1952 - idev->nd_parms->reachable_time = 1953 - neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)); 1951 + if (ctl->data == NEIGH_VAR_PTR(idev->nd_parms, BASE_REACHABLE_TIME)) 1952 + neigh_set_reach_time(idev->nd_parms); 1953 + 1954 1954 WRITE_ONCE(idev->tstamp, jiffies); 1955 1955 inet6_ifinfo_notify(RTM_NEWLINK, idev); 1956 1956 in6_dev_put(idev);