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.

Merge branch 'neighbour-convert-rtm_getneightbl-and-rtm_setneightbl-to-rcu'

Kuniyuki Iwashima says:

====================
neighbour: Convert RTM_GETNEIGHTBL and RTM_SETNEIGHTBL to RCU.

Patch 1 & 2 are prep for RCU conversion for RTM_GETNEIGHTBL.

Patch 3 & 4 converts RTM_GETNEIGHTBL and RTM_SETNEIGHTBL to RCU.

Patch 5 converts the neighbour table rwlock to the plain spinlock.
====================

Link: https://patch.msgid.link/20251022054004.2514876-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+87 -77
+13 -4
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) ··· 238 236 atomic_t gc_entries; 239 237 struct list_head gc_list; 240 238 struct list_head managed_list; 241 - rwlock_t lock; 239 + spinlock_t lock; 242 240 unsigned long last_rand; 243 241 struct neigh_statistics __percpu *stats; 244 242 struct neigh_hash_table __rcu *nht; ··· 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);
+2 -2
net/atm/clip.c
··· 168 168 169 169 static void idle_timer_check(struct timer_list *unused) 170 170 { 171 - write_lock(&arp_tbl.lock); 171 + spin_lock(&arp_tbl.lock); 172 172 __neigh_for_each_release(&arp_tbl, neigh_check_cb); 173 173 mod_timer(&idle_timer, jiffies + CLIP_CHECK_INTERVAL * HZ); 174 - write_unlock(&arp_tbl.lock); 174 + spin_unlock(&arp_tbl.lock); 175 175 } 176 176 177 177 static int clip_arp_rcv(struct sk_buff *skb)
+66 -65
net/core/neighbour.c
··· 81 81 } 82 82 83 83 /* 84 - Neighbour hash table buckets are protected with rwlock tbl->lock. 84 + Neighbour hash table buckets are protected with tbl->lock. 85 85 86 86 - All the scans/updates to hash buckets MUST be made under this lock. 87 87 - NOTHING clever should be made under this lock: no callbacks ··· 149 149 { 150 150 bool on_gc_list, exempt_from_gc; 151 151 152 - write_lock_bh(&n->tbl->lock); 152 + spin_lock_bh(&n->tbl->lock); 153 153 write_lock(&n->lock); 154 154 if (n->dead) 155 155 goto out; ··· 172 172 } 173 173 out: 174 174 write_unlock(&n->lock); 175 - write_unlock_bh(&n->tbl->lock); 175 + spin_unlock_bh(&n->tbl->lock); 176 176 } 177 177 178 178 static void neigh_update_managed_list(struct neighbour *n) 179 179 { 180 180 bool on_managed_list, add_to_managed; 181 181 182 - write_lock_bh(&n->tbl->lock); 182 + spin_lock_bh(&n->tbl->lock); 183 183 write_lock(&n->lock); 184 184 if (n->dead) 185 185 goto out; ··· 193 193 list_add_tail(&n->managed_list, &n->tbl->managed_list); 194 194 out: 195 195 write_unlock(&n->lock); 196 - write_unlock_bh(&n->tbl->lock); 196 + spin_unlock_bh(&n->tbl->lock); 197 197 } 198 198 199 199 static void neigh_update_flags(struct neighbour *neigh, u32 flags, int *notify, ··· 263 263 264 264 NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs); 265 265 266 - write_lock_bh(&tbl->lock); 266 + spin_lock_bh(&tbl->lock); 267 267 268 268 list_for_each_entry_safe(n, tmp, &tbl->gc_list, gc_list) { 269 269 if (refcount_read(&n->refcnt) == 1) { ··· 292 292 293 293 WRITE_ONCE(tbl->last_flush, jiffies); 294 294 unlock: 295 - write_unlock_bh(&tbl->lock); 295 + spin_unlock_bh(&tbl->lock); 296 296 297 297 return shrunk; 298 298 } ··· 454 454 455 455 void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev) 456 456 { 457 - write_lock_bh(&tbl->lock); 457 + spin_lock_bh(&tbl->lock); 458 458 neigh_flush_dev(tbl, dev, false); 459 - write_unlock_bh(&tbl->lock); 459 + spin_unlock_bh(&tbl->lock); 460 460 } 461 461 EXPORT_SYMBOL(neigh_changeaddr); 462 462 463 463 static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev, 464 464 bool skip_perm) 465 465 { 466 - write_lock_bh(&tbl->lock); 466 + spin_lock_bh(&tbl->lock); 467 467 if (likely(dev)) { 468 468 neigh_flush_dev(tbl, dev, skip_perm); 469 469 } else { 470 470 DEBUG_NET_WARN_ON_ONCE(skip_perm); 471 471 neigh_flush_table(tbl); 472 472 } 473 - write_unlock_bh(&tbl->lock); 473 + spin_unlock_bh(&tbl->lock); 474 474 475 475 pneigh_ifdown(tbl, dev, skip_perm); 476 476 pneigh_queue_purge(&tbl->proxy_queue, dev ? dev_net(dev) : NULL, ··· 687 687 688 688 n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1); 689 689 690 - write_lock_bh(&tbl->lock); 690 + spin_lock_bh(&tbl->lock); 691 691 nht = rcu_dereference_protected(tbl->nht, 692 692 lockdep_is_held(&tbl->lock)); 693 693 ··· 722 722 hlist_add_head_rcu(&n->dev_list, 723 723 neigh_get_dev_table(dev, tbl->family)); 724 724 725 - write_unlock_bh(&tbl->lock); 725 + spin_unlock_bh(&tbl->lock); 726 726 neigh_dbg(2, "neigh %p is created\n", n); 727 727 rc = n; 728 728 out: 729 729 return rc; 730 730 out_tbl_unlock: 731 - write_unlock_bh(&tbl->lock); 731 + spin_unlock_bh(&tbl->lock); 732 732 out_neigh_release: 733 733 if (!exempt_from_gc) 734 734 atomic_dec(&tbl->gc_entries); ··· 982 982 983 983 NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs); 984 984 985 - write_lock_bh(&tbl->lock); 985 + spin_lock_bh(&tbl->lock); 986 986 nht = rcu_dereference_protected(tbl->nht, 987 987 lockdep_is_held(&tbl->lock)); 988 988 ··· 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)) ··· 1036 1037 * It's fine to release lock here, even if hash table 1037 1038 * grows while we are preempted. 1038 1039 */ 1039 - write_unlock_bh(&tbl->lock); 1040 + spin_unlock_bh(&tbl->lock); 1040 1041 cond_resched(); 1041 - write_lock_bh(&tbl->lock); 1042 + spin_lock_bh(&tbl->lock); 1042 1043 nht = rcu_dereference_protected(tbl->nht, 1043 1044 lockdep_is_held(&tbl->lock)); 1044 1045 } ··· 1049 1050 */ 1050 1051 queue_delayed_work(system_power_efficient_wq, &tbl->gc_work, 1051 1052 NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1); 1052 - write_unlock_bh(&tbl->lock); 1053 + spin_unlock_bh(&tbl->lock); 1053 1054 } 1054 1055 1055 1056 static __inline__ int neigh_max_probes(struct neighbour *n) ··· 1641 1642 managed_work.work); 1642 1643 struct neighbour *neigh; 1643 1644 1644 - write_lock_bh(&tbl->lock); 1645 + spin_lock_bh(&tbl->lock); 1645 1646 list_for_each_entry(neigh, &tbl->managed_list, managed_list) 1646 1647 neigh_event_send_probe(neigh, NULL, false); 1647 1648 queue_delayed_work(system_power_efficient_wq, &tbl->managed_work, 1648 1649 NEIGH_VAR(&tbl->parms, INTERVAL_PROBE_TIME_MS)); 1649 - write_unlock_bh(&tbl->lock); 1650 + spin_unlock_bh(&tbl->lock); 1650 1651 } 1651 1652 1652 1653 static void neigh_proxy_process(struct timer_list *t) ··· 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; ··· 1761 1763 return NULL; 1762 1764 } 1763 1765 1764 - write_lock_bh(&tbl->lock); 1765 - list_add(&p->list, &tbl->parms.list); 1766 - write_unlock_bh(&tbl->lock); 1766 + spin_lock_bh(&tbl->lock); 1767 + list_add_rcu(&p->list, &tbl->parms.list); 1768 + spin_unlock_bh(&tbl->lock); 1767 1769 1768 1770 neigh_parms_data_state_cleanall(p); 1769 1771 } ··· 1783 1785 { 1784 1786 if (!parms || parms == &tbl->parms) 1785 1787 return; 1786 - write_lock_bh(&tbl->lock); 1787 - list_del(&parms->list); 1788 + 1789 + spin_lock_bh(&tbl->lock); 1790 + list_del_rcu(&parms->list); 1788 1791 parms->dead = 1; 1789 - write_unlock_bh(&tbl->lock); 1792 + spin_unlock_bh(&tbl->lock); 1793 + 1790 1794 netdev_put(parms->dev, &parms->dev_tracker); 1791 1795 call_rcu(&parms->rcu_head, neigh_rcu_free_parms); 1792 1796 } ··· 1810 1810 list_add(&tbl->parms.list, &tbl->parms_list); 1811 1811 write_pnet(&tbl->parms.net, &init_net); 1812 1812 refcount_set(&tbl->parms.refcnt, 1); 1813 - tbl->parms.reachable_time = 1814 - neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME)); 1813 + neigh_set_reach_time(&tbl->parms); 1815 1814 tbl->parms.qlen = 0; 1816 1815 1817 1816 tbl->stats = alloc_percpu(struct neigh_statistics); ··· 1837 1838 else 1838 1839 WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN); 1839 1840 1840 - rwlock_init(&tbl->lock); 1841 + spin_lock_init(&tbl->lock); 1841 1842 mutex_init(&tbl->phash_lock); 1842 1843 1843 1844 INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work); ··· 1980 1981 err = __neigh_update(neigh, NULL, NUD_FAILED, 1981 1982 NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN, 1982 1983 NETLINK_CB(skb).portid, extack); 1983 - write_lock_bh(&tbl->lock); 1984 + spin_lock_bh(&tbl->lock); 1984 1985 neigh_release(neigh); 1985 1986 neigh_remove_one(neigh); 1986 - write_unlock_bh(&tbl->lock); 1987 + spin_unlock_bh(&tbl->lock); 1987 1988 1988 1989 out: 1989 1990 return err; ··· 2178 2179 return -ENOBUFS; 2179 2180 2180 2181 if ((parms->dev && 2181 - nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) || 2182 + nla_put_u32(skb, NDTPA_IFINDEX, READ_ONCE(parms->dev->ifindex))) || 2182 2183 nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) || 2183 2184 nla_put_u32(skb, NDTPA_QUEUE_LENBYTES, 2184 2185 NEIGH_VAR(parms, QUEUE_LEN_BYTES)) || ··· 2193 2194 NEIGH_VAR(parms, MCAST_PROBES)) || 2194 2195 nla_put_u32(skb, NDTPA_MCAST_REPROBES, 2195 2196 NEIGH_VAR(parms, MCAST_REPROBES)) || 2196 - nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time, 2197 + nla_put_msecs(skb, NDTPA_REACHABLE_TIME, READ_ONCE(parms->reachable_time), 2197 2198 NDTPA_PAD) || 2198 2199 nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME, 2199 2200 NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) || ··· 2230 2231 return -EMSGSIZE; 2231 2232 2232 2233 ndtmsg = nlmsg_data(nlh); 2233 - 2234 - read_lock_bh(&tbl->lock); 2235 2234 ndtmsg->ndtm_family = tbl->family; 2236 2235 ndtmsg->ndtm_pad1 = 0; 2237 2236 ndtmsg->ndtm_pad2 = 0; ··· 2255 2258 .ndtc_proxy_qlen = READ_ONCE(tbl->proxy_queue.qlen), 2256 2259 }; 2257 2260 2258 - rcu_read_lock(); 2259 2261 nht = rcu_dereference(tbl->nht); 2260 2262 ndc.ndtc_hash_rnd = nht->hash_rnd[0]; 2261 2263 ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1); 2262 - rcu_read_unlock(); 2263 2264 2264 2265 if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc)) 2265 2266 goto nla_put_failure; ··· 2295 2300 if (neightbl_fill_parms(skb, &tbl->parms) < 0) 2296 2301 goto nla_put_failure; 2297 2302 2298 - read_unlock_bh(&tbl->lock); 2299 2303 nlmsg_end(skb, nlh); 2300 2304 return 0; 2301 2305 2302 2306 nla_put_failure: 2303 - read_unlock_bh(&tbl->lock); 2304 2307 nlmsg_cancel(skb, nlh); 2305 2308 return -EMSGSIZE; 2306 2309 } ··· 2317 2324 return -EMSGSIZE; 2318 2325 2319 2326 ndtmsg = nlmsg_data(nlh); 2320 - 2321 - read_lock_bh(&tbl->lock); 2322 2327 ndtmsg->ndtm_family = tbl->family; 2323 2328 ndtmsg->ndtm_pad1 = 0; 2324 2329 ndtmsg->ndtm_pad2 = 0; ··· 2325 2334 neightbl_fill_parms(skb, parms) < 0) 2326 2335 goto errout; 2327 2336 2328 - read_unlock_bh(&tbl->lock); 2329 2337 nlmsg_end(skb, nlh); 2330 2338 return 0; 2331 2339 errout: 2332 - read_unlock_bh(&tbl->lock); 2333 2340 nlmsg_cancel(skb, nlh); 2334 2341 return -EMSGSIZE; 2335 2342 } ··· 2364 2375 struct netlink_ext_ack *extack) 2365 2376 { 2366 2377 struct net *net = sock_net(skb->sk); 2378 + struct nlattr *tb[NDTA_MAX + 1]; 2367 2379 struct neigh_table *tbl; 2368 2380 struct ndtmsg *ndtmsg; 2369 - struct nlattr *tb[NDTA_MAX+1]; 2370 2381 bool found = false; 2371 2382 int err, tidx; 2372 2383 ··· 2382 2393 2383 2394 ndtmsg = nlmsg_data(nlh); 2384 2395 2396 + rcu_read_lock(); 2397 + 2385 2398 for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { 2386 - tbl = rcu_dereference_rtnl(neigh_tables[tidx]); 2399 + tbl = rcu_dereference(neigh_tables[tidx]); 2387 2400 if (!tbl) 2388 2401 continue; 2402 + 2389 2403 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) 2390 2404 continue; 2405 + 2391 2406 if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) { 2392 2407 found = true; 2393 2408 break; 2394 2409 } 2395 2410 } 2396 2411 2397 - if (!found) 2398 - return -ENOENT; 2412 + if (!found) { 2413 + rcu_read_unlock(); 2414 + err = -ENOENT; 2415 + goto errout; 2416 + } 2399 2417 2400 2418 /* 2401 2419 * We acquire tbl->lock to be nice to the periodic timers and 2402 2420 * make sure they always see a consistent set of values. 2403 2421 */ 2404 - write_lock_bh(&tbl->lock); 2422 + spin_lock_bh(&tbl->lock); 2405 2423 2406 2424 if (tb[NDTA_PARMS]) { 2407 2425 struct nlattr *tbp[NDTPA_MAX+1]; ··· 2471 2475 * only be effective after the next time neigh_periodic_work 2472 2476 * decides to recompute it (can be multiple minutes) 2473 2477 */ 2474 - p->reachable_time = 2475 - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); 2478 + neigh_set_reach_time(p); 2476 2479 break; 2477 2480 case NDTPA_GC_STALETIME: 2478 2481 NEIGH_VAR_SET(p, GC_STALETIME, ··· 2527 2532 err = 0; 2528 2533 2529 2534 errout_tbl_lock: 2530 - write_unlock_bh(&tbl->lock); 2535 + spin_unlock_bh(&tbl->lock); 2536 + rcu_read_unlock(); 2531 2537 errout: 2532 2538 return err; 2533 2539 } ··· 2575 2579 2576 2580 family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family; 2577 2581 2582 + rcu_read_lock(); 2583 + 2578 2584 for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { 2579 2585 struct neigh_parms *p; 2580 2586 2581 - tbl = rcu_dereference_rtnl(neigh_tables[tidx]); 2587 + tbl = rcu_dereference(neigh_tables[tidx]); 2582 2588 if (!tbl) 2583 2589 continue; 2584 2590 ··· 2594 2596 2595 2597 nidx = 0; 2596 2598 p = list_next_entry(&tbl->parms, list); 2597 - list_for_each_entry_from(p, &tbl->parms_list, list) { 2599 + list_for_each_entry_from_rcu(p, &tbl->parms_list, list) { 2598 2600 if (!net_eq(neigh_parms_net(p), net)) 2599 2601 continue; 2600 2602 ··· 2614 2616 neigh_skip = 0; 2615 2617 } 2616 2618 out: 2619 + rcu_read_unlock(); 2620 + 2617 2621 cb->args[0] = tidx; 2618 2622 cb->args[1] = nidx; 2619 2623 ··· 3127 3127 rcu_read_lock(); 3128 3128 nht = rcu_dereference(tbl->nht); 3129 3129 3130 - read_lock_bh(&tbl->lock); /* avoid resizes */ 3130 + spin_lock_bh(&tbl->lock); /* avoid resizes */ 3131 3131 for (chain = 0; chain < (1 << nht->hash_shift); chain++) { 3132 3132 struct neighbour *n; 3133 3133 3134 3134 neigh_for_each_in_bucket(n, &nht->hash_heads[chain]) 3135 3135 cb(n, cookie); 3136 3136 } 3137 - read_unlock_bh(&tbl->lock); 3137 + spin_unlock_bh(&tbl->lock); 3138 3138 rcu_read_unlock(); 3139 3139 } 3140 3140 EXPORT_SYMBOL(neigh_for_each); ··· 3404 3404 3405 3405 rcu_read_lock(); 3406 3406 state->nht = rcu_dereference(tbl->nht); 3407 - read_lock_bh(&tbl->lock); 3407 + spin_lock_bh(&tbl->lock); 3408 3408 3409 3409 return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN; 3410 3410 } ··· 3444 3444 struct neigh_seq_state *state = seq->private; 3445 3445 struct neigh_table *tbl = state->tbl; 3446 3446 3447 - read_unlock_bh(&tbl->lock); 3447 + spin_unlock_bh(&tbl->lock); 3448 3448 rcu_read_unlock(); 3449 3449 } 3450 3450 EXPORT_SYMBOL(neigh_seq_stop); ··· 3721 3721 * only be effective after the next time neigh_periodic_work 3722 3722 * decides to recompute it 3723 3723 */ 3724 - p->reachable_time = 3725 - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); 3724 + neigh_set_reach_time(p); 3726 3725 } 3727 3726 return ret; 3728 3727 } ··· 3917 3918 {.msgtype = RTM_DELNEIGH, .doit = neigh_delete}, 3918 3919 {.msgtype = RTM_GETNEIGH, .doit = neigh_get, .dumpit = neigh_dump_info, 3919 3920 .flags = RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED}, 3920 - {.msgtype = RTM_GETNEIGHTBL, .dumpit = neightbl_dump_info}, 3921 - {.msgtype = RTM_SETNEIGHTBL, .doit = neightbl_set}, 3921 + {.msgtype = RTM_GETNEIGHTBL, .dumpit = neightbl_dump_info, 3922 + .flags = RTNL_FLAG_DUMP_UNLOCKED}, 3923 + {.msgtype = RTM_SETNEIGHTBL, .doit = neightbl_set, 3924 + .flags = RTNL_FLAG_DOIT_UNLOCKED}, 3922 3925 }; 3923 3926 3924 3927 static int __init neigh_init(void)
+2 -2
net/ipv4/arp.c
··· 1217 1217 err = neigh_update(neigh, NULL, NUD_FAILED, 1218 1218 NEIGH_UPDATE_F_OVERRIDE| 1219 1219 NEIGH_UPDATE_F_ADMIN, 0); 1220 - write_lock_bh(&tbl->lock); 1220 + spin_lock_bh(&tbl->lock); 1221 1221 neigh_release(neigh); 1222 1222 neigh_remove_one(neigh); 1223 - write_unlock_bh(&tbl->lock); 1223 + spin_unlock_bh(&tbl->lock); 1224 1224 } 1225 1225 1226 1226 return err;
+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);