• J
    genhd: Fix BUG in blkdev_open() · 56c0908c
    Jan Kara 提交于
    When two blkdev_open() calls for a partition race with device removal
    and recreation, we can hit BUG_ON(!bd_may_claim(bdev, whole, holder)) in
    blkdev_open(). The race can happen as follows:
    
    CPU0				CPU1			CPU2
    							del_gendisk()
    							  bdev_unhash_inode(part1);
    
    blkdev_open(part1, O_EXCL)	blkdev_open(part1, O_EXCL)
      bdev = bd_acquire()		  bdev = bd_acquire()
      blkdev_get(bdev)
        bd_start_claiming(bdev)
          - finds old inode 'whole'
          bd_prepare_to_claim() -> 0
    							  bdev_unhash_inode(whole);
    							<device removed>
    							<new device under same
    							 number created>
    				  blkdev_get(bdev);
    				    bd_start_claiming(bdev)
    				      - finds new inode 'whole'
    				      bd_prepare_to_claim()
    					- this also succeeds as we have
    					  different 'whole' here...
    					- bad things happen now as we
    					  have two exclusive openers of
    					  the same bdev
    
    The problem here is that block device opens can see various intermediate
    states while gendisk is shutting down and then being recreated.
    
    We fix the problem by introducing new lookup_sem in gendisk that
    synchronizes gendisk deletion with get_gendisk() and furthermore by
    making sure that get_gendisk() does not return gendisk that is being (or
    has been) deleted. This makes sure that once we ever manage to look up
    newly created bdev inode, we are also guaranteed that following
    get_gendisk() will either return failure (and we fail open) or it
    returns gendisk for the new device and following bdget_disk() will
    return new bdev inode (i.e., blkdev_open() follows the path as if it is
    completely run after new device is created).
    Reported-and-analyzed-by: NHou Tao <houtao1@huawei.com>
    Tested-by: NHou Tao <houtao1@huawei.com>
    Signed-off-by: NJan Kara <jack@suse.cz>
    Signed-off-by: NJens Axboe <axboe@kernel.dk>
    56c0908c
genhd.h 22.9 KB