• Tejun Heo's avatar
    percpu_ref: allow operation mode switching operations to be called concurrently · 33e465ce
    Tejun Heo authored
    percpu_ref initially didn't have explicit mode switching operations.
    It started out in percpu mode and switched to atomic mode on kill and
    then released.  Ensuring that kill operation is initiated only after
    init completes was naturally the caller's responsibility.
    
    percpu_ref_reinit() was introduced later but it didn't shift the
    synchronization responsibility.  Reinit can't be performed until kill
    is confirmed, so there was nothing to worry about
    synchronization-wise.  Also, as both reinit and kill manipulate the
    base reference, invocations of the same function couldn't be allowed
    to race each other.
    
    The latest additions of percpu_ref_switch_to_atomic/percpu() changed
    the situation.  These two functions can be called any time as long as
    the percpu_ref is between init and exit and thus there are valid valid
    usage scenarios where these new functions race with each other or
    against reinit/kill.  Mostly from inertia, f47ad457 ("percpu_ref:
    decouple switching to percpu mode and reinit") still left
    synchronization among percpu mode switching operations to its users.
    
    That the new switch functions can be freely mixed with kill/reinit but
    the operations themselves should be synchronized is too subtle a
    requirement and led to a very subtle race condition in blk-mq freezing
    path.
    
    This patch fixes the situation by introducing percpu_ref_switch_lock
    to protect mode switching operations.  This ensures that percpu-ref
    users don't have to worry about mode changing operations racing
    against each other, e.g. switch_to_percpu against kill, as long as the
    sequence of operations is valid.
    Signed-off-by: default avatarTejun Heo <tj@kernel.org>
    Reported-by: default avatarAkinobu Mita <akinobu.mita@gmail.com>
    Link: http://lkml.kernel.org/g/1443287365-4244-7-git-send-email-akinobu.mita@gmail.com
    Fixes: f47ad457 ("percpu_ref: decouple switching to percpu mode and reinit")
    33e465ce
percpu-refcount.c 11.7 KB