• Mikulas Patocka's avatar
    Fix a crash when block device is read and block size is changed at the same time · b87570f5
    Mikulas Patocka authored
    The kernel may crash when block size is changed and I/O is issued
    simultaneously.
    
    Because some subsystems (udev or lvm) may read any block device anytime,
    the bug actually puts any code that changes a block device size in
    jeopardy.
    
    The crash can be reproduced if you place "msleep(1000)" to
    blkdev_get_blocks just before "bh->b_size = max_blocks <<
    inode->i_blkbits;".
    Then, run "dd if=/dev/ram0 of=/dev/null bs=4k count=1 iflag=direct"
    While it is waiting in msleep, run "blockdev --setbsz 2048 /dev/ram0"
    You get a BUG.
    
    The direct and non-direct I/O is written with the assumption that block
    size does not change. It doesn't seem practical to fix these crashes
    one-by-one there may be many crash possibilities when block size changes
    at a certain place and it is impossible to find them all and verify the
    code.
    
    This patch introduces a new rw-lock bd_block_size_semaphore. The lock is
    taken for read during I/O. It is taken for write when changing block
    size. Consequently, block size can't be changed while I/O is being
    submitted.
    
    For asynchronous I/O, the patch only prevents block size change while
    the I/O is being submitted. The block size can change when the I/O is in
    progress or when the I/O is being finished. This is acceptable because
    there are no accesses to block size when asynchronous I/O is being
    finished.
    
    The patch prevents block size changing while the device is mapped with
    mmap.
    Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
    Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
    b87570f5
block_dev.c 44.1 KB