• Jeff Layton's avatar
    ceph: take snap_empty_lock atomically with snaprealm refcount change · 8434ffe7
    Jeff Layton authored
    There is a race in ceph_put_snap_realm. The change to the nref and the
    spinlock acquisition are not done atomically, so you could decrement
    nref, and before you take the spinlock, the nref is incremented again.
    At that point, you end up putting it on the empty list when it
    shouldn't be there. Eventually __cleanup_empty_realms runs and frees
    it when it's still in-use.
    
    Fix this by protecting the 1->0 transition with atomic_dec_and_lock,
    and just drop the spinlock if we can get the rwsem.
    
    Because these objects can also undergo a 0->1 refcount transition, we
    must protect that change as well with the spinlock. Increment locklessly
    unless the value is at 0, in which case we take the spinlock, increment
    and then take it off the empty list if it did the 0->1 transition.
    
    With these changes, I'm removing the dout() messages from these
    functions, as well as in __put_snap_realm. They've always been racy, and
    it's better to not print values that may be misleading.
    
    Cc: stable@vger.kernel.org
    URL: https://tracker.ceph.com/issues/46419Reported-by: default avatarMark Nelson <mnelson@redhat.com>
    Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
    Reviewed-by: default avatarLuis Henriques <lhenriques@suse.de>
    Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
    8434ffe7
snap.c 31.9 KB