]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: core: neighbour: Add a neigh_fill_info() helper for when lock not held
authorPetr Machata <petrm@nvidia.com>
Wed, 21 Jan 2026 16:43:35 +0000 (17:43 +0100)
committerJakub Kicinski <kuba@kernel.org>
Sun, 25 Jan 2026 22:57:36 +0000 (14:57 -0800)
The netlink message needs to be formatted and sent inside the critical
section where the neighbor is changed, so that it reflects the
notified-upon neighbor state. Because it will happen inside an already
existing critical section, it has to assume that the neighbor lock is held.
Add a helper __neigh_fill_info(), which is like neigh_fill_info(), but
makes this assumption. Convert neigh_fill_info() to a wrapper around this
new helper.

Signed-off-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/7ec20113d5d809200e3534d3ed8f0004514914b8.1769012464.git.petrm@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/neighbour.c

index 96a3b1a93252a5b2cc9b73bd650f67545a313742..6cdd93dfa3ea9dd8b2336245580a9faaec07da3f 100644 (file)
@@ -2622,8 +2622,8 @@ out:
        return skb->len;
 }
 
-static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
-                          u32 pid, u32 seq, int type, unsigned int flags)
+static int __neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
+                            u32 pid, u32 seq, int type, unsigned int flags)
 {
        u32 neigh_flags, neigh_flags_ext;
        unsigned long now = jiffies;
@@ -2649,23 +2649,19 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
        if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
                goto nla_put_failure;
 
-       read_lock_bh(&neigh->lock);
        ndm->ndm_state   = neigh->nud_state;
        if (neigh->nud_state & NUD_VALID) {
                char haddr[MAX_ADDR_LEN];
 
                neigh_ha_snapshot(haddr, neigh, neigh->dev);
-               if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
-                       read_unlock_bh(&neigh->lock);
+               if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0)
                        goto nla_put_failure;
-               }
        }
 
        ci.ndm_used      = jiffies_to_clock_t(now - neigh->used);
        ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
        ci.ndm_updated   = jiffies_to_clock_t(now - neigh->updated);
        ci.ndm_refcnt    = refcount_read(&neigh->refcnt) - 1;
-       read_unlock_bh(&neigh->lock);
 
        if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
            nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
@@ -2684,6 +2680,20 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
+static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
+                          u32 pid, u32 seq, int type, unsigned int flags)
+       __releases(neigh->lock)
+       __acquires(neigh->lock)
+{
+       int err;
+
+       read_lock_bh(&neigh->lock);
+       err = __neigh_fill_info(skb, neigh, pid, seq, type, flags);
+       read_unlock_bh(&neigh->lock);
+
+       return err;
+}
+
 static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
                            u32 pid, u32 seq, int type, unsigned int flags,
                            struct neigh_table *tbl)