On 12/09/2018 09:12 PM, Eric Dumazet wrote:

> What protects gc_list linkage ?
> 
> We can not use list_del_init(&n->gc_list);                    or 
>                list_add_tail(&n->gc_list, &n->tbl->gc_list);
> 
> if tbl->lock is not held.
> 
> It seems to me this patch needs more care.
> 

I am playing with a LOCKDEP assist :

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 
c3b58712e98b9157ca717951da40eb5ae2fe810b..213e56a3816918e599f9a658bcb851711c578f7b
 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -122,6 +122,7 @@ static void neigh_mark_dead(struct neighbour *n)
 {
        n->dead = 1;
        if (!list_empty(&n->gc_list)) {
+               WARN_ON_ONCE(debug_locks && !lockdep_is_held(&n->tbl->lock));
                list_del_init(&n->gc_list);
                atomic_dec(&n->tbl->gc_entries);
        }
@@ -138,10 +139,12 @@ static void neigh_change_state(struct neighbour *n, u8 
new)
         * add to the gc list if new state is not permanent
         */
        if (new_is_perm && on_gc_list) {
+               WARN_ON_ONCE(debug_locks && !lockdep_is_held(&n->tbl->lock));
                list_del_init(&n->gc_list);
                atomic_dec(&n->tbl->gc_entries);
        } else if (!new_is_perm && !on_gc_list) {
                /* add entries to the tail; cleaning removes from the front */
+               WARN_ON_ONCE(debug_locks && !lockdep_is_held(&n->tbl->lock));
                list_add_tail(&n->gc_list, &n->tbl->gc_list);
                atomic_inc(&n->tbl->gc_entries);
        }
@@ -391,8 +394,10 @@ static struct neighbour *neigh_alloc(struct neigh_table 
*tbl,
        refcount_set(&n->refcnt, 1);
        n->dead           = 1;
 
-       if (!permanent)
+       if (!permanent) {
+               WARN_ON_ONCE(debug_locks && !lockdep_is_held(&n->tbl->lock));
                list_add_tail(&n->gc_list, &n->tbl->gc_list);
+       }
        else
                INIT_LIST_HEAD(&n->gc_list);
 

Reply via email to