• NeilBrown's avatar
    block_dev: don't test bdev->bd_contains when it is not stable · d80411de
    NeilBrown authored
    commit bcc7f5b4 upstream.
    
    bdev->bd_contains is not stable before calling __blkdev_get().
    When __blkdev_get() is called on a parition with ->bd_openers == 0
    it sets
      bdev->bd_contains = bdev;
    which is not correct for a partition.
    After a call to __blkdev_get() succeeds, ->bd_openers will be > 0
    and then ->bd_contains is stable.
    
    When FMODE_EXCL is used, blkdev_get() calls
       bd_start_claiming() ->  bd_prepare_to_claim() -> bd_may_claim()
    
    This call happens before __blkdev_get() is called, so ->bd_contains
    is not stable.  So bd_may_claim() cannot safely use ->bd_contains.
    It currently tries to use it, and this can lead to a BUG_ON().
    
    This happens when a whole device is already open with a bd_holder (in
    use by dm in my particular example) and two threads race to open a
    partition of that device for the first time, one opening with O_EXCL and
    one without.
    
    The thread that doesn't use O_EXCL gets through blkdev_get() to
    __blkdev_get(), gains the ->bd_mutex, and sets bdev->bd_contains = bdev;
    
    Immediately thereafter the other thread, using FMODE_EXCL, calls
    bd_start_claiming() from blkdev_get().  This should fail because the
    whole device has a holder, but because bdev->bd_contains == bdev
    bd_may_claim() incorrectly reports success.
    This thread continues and blocks on bd_mutex.
    
    The first thread then sets bdev->bd_contains correctly and drops the mutex.
    The thread using FMODE_EXCL then continues and when it calls bd_may_claim()
    again in:
    			BUG_ON(!bd_may_claim(bdev, whole, holder));
    The BUG_ON fires.
    
    Fix this by removing the dependency on ->bd_contains in
    bd_may_claim().  As bd_may_claim() has direct access to the whole
    device, it can simply test if the target bdev is the whole device.
    
    Fixes: 6b4517a7 ("block: implement bd_claiming and claiming block")
    Signed-off-by: default avatarNeilBrown <neilb@suse.com>
    Signed-off-by: default avatarJens Axboe <axboe@fb.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    d80411de
block_dev.c 46.4 KB