]> git.hungrycats.org Git - linux/commit
[PATCH] loop setup race fix
authorAndrew Morton <akpm@osdl.org>
Fri, 12 Mar 2004 00:16:17 +0000 (16:16 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Fri, 12 Mar 2004 00:16:17 +0000 (16:16 -0800)
commit238a43a0f005e50e466690241b6310ae8d5c2cce
tree11e38dbd12fb08213489d4c45d6dec8f0208ee9e
parent275da6a305c6b1ee5283011ed5757d4cc45c5994
[PATCH] loop setup race fix

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.
drivers/block/loop.c
fs/block_dev.c
include/linux/fs.h