• Andrew Morton's avatar
    [PATCH] loop setup race fix · 238a43a0
    Andrew Morton authored
    From: Chris Mason <mason@suse.com>
    
    There's a race in loopback setup, it's easiest to trigger with one or more
    procs doing loopback mounts at the same time.  The problem is that
    fs/block_dev.c:do_open() only calls bdev_set_size on the first open.
    Picture two procs:
    
    proc1: mount -o loop file1 mnt1
    proc2: mount -o loop file2 mnt2
    
    proc1                   proc2
    open /dev/loop0                         # bd_openers now 1
    do_open
     bd_set_size(bdev, 0)                   # loop unbound, so bdev size is 0
                            open /dev/loop0 # bd_openers now 2
    loop_set_fd                             # disk capacity now correct, but
    				        # bdev not updated
    mount /dev/loop0 /mnt
    do_open
    
    Because bd_openers != 0 for the last do_open, bd_set_size is not called
    again and a size of 0 is used.  This eventually leads to an oops when the
    loop device is unmounted, because fsync_bdev calls block_write_full_page
    who decides every page on the block device is outside i_size and unmaps
    them.
    
    When ext2 or reiserfs try to sync a metadata buffer, we get an oops on
    because the buffers are no longer mapped.
    
    The patch below changes loop_set_fd and loop_clr_fd to also manipulate the
    size of the block device, which fixes things for me.
    238a43a0
block_dev.c 21 KB