• D
    ipv6: addrconf: cleanup locking in ipv6_add_addr · f3d9832e
    David Ahern 提交于
    ipv6_add_addr is called in process context with rtnl lock held
    (e.g., manual config of an address) or during softirq processing
    (e.g., autoconf and address from a router advertisement).
    
    Currently, ipv6_add_addr calls rcu_read_lock_bh shortly after entry
    and does not call unlock until exit, minus the call around the address
    validator notifier. Similarly, addrconf_hash_lock is taken after the
    validator notifier and held until exit. This forces the allocation of
    inet6_ifaddr to always be atomic.
    
    Refactor ipv6_add_addr as follows:
    1. add an input boolean to discriminate the call path (process context
       or softirq). This new flag controls whether the alloc can be done
       with GFP_KERNEL or GFP_ATOMIC.
    
    2. Move the rcu_read_lock_bh and unlock calls only around functions that
       do rcu updates.
    
    3. Remove the in6_dev_hold and put added by 3ad7d246 ("Ipvlan should
       return an error when an address is already in use."). This was done
       presumably because rcu_read_unlock_bh needs to be called before calling
       the validator. Since rcu_read_lock is not needed before the validator
       runs revert the hold and put added by 3ad7d246 and only do the
       hold when setting ifp->idev.
    
    4. move duplicate address check and insertion of new address in the global
       address hash into a helper. The helper is called after an ifa is
       allocated and filled in.
    
    This allows the ifa for manually configured addresses to be done with
    GFP_KERNEL and reduces the overall amount of time with rcu_read_lock held
    and hash table spinlock held.
    Signed-off-by: NDavid Ahern <dsahern@gmail.com>
    Signed-off-by: NDavid S. Miller <davem@davemloft.net>
    f3d9832e
addrconf.c 159.8 KB