• Michal Kubeček's avatar
    ipv6: prevent fib6_run_gc() contention · 5317d9af
    Michal Kubeček authored
    commit 2ac3ac8f upstream.
    
    On a high-traffic router with many processors and many IPv6 dst
    entries, soft lockup in fib6_run_gc() can occur when number of
    entries reaches gc_thresh.
    
    This happens because fib6_run_gc() uses fib6_gc_lock to allow
    only one thread to run the garbage collector but ip6_dst_gc()
    doesn't update net->ipv6.ip6_rt_last_gc until fib6_run_gc()
    returns. On a system with many entries, this can take some time
    so that in the meantime, other threads pass the tests in
    ip6_dst_gc() (ip6_rt_last_gc is still not updated) and wait for
    the lock. They then have to run the garbage collector one after
    another which blocks them for quite long.
    
    Resolve this by replacing special value ~0UL of expire parameter
    to fib6_run_gc() by explicit "force" parameter to choose between
    spin_lock_bh() and spin_trylock_bh() and call fib6_run_gc() with
    force=false if gc_thresh is reached but not max_size.
    Signed-off-by: default avatarMichal Kubecek <mkubecek@suse.cz>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    [lizf: Backported to 3.4: adjust context]
    Signed-off-by: default avatarZefan Li <lizefan@huawei.com>
    5317d9af
ndisc.c 46.3 KB