summaryrefslogtreecommitdiff
path: root/include/linux/fs.h
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-03-11 16:16:17 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-03-11 16:16:17 -0800
commit238a43a0f005e50e466690241b6310ae8d5c2cce (patch)
tree11e38dbd12fb08213489d4c45d6dec8f0208ee9e /include/linux/fs.h
parent275da6a305c6b1ee5283011ed5757d4cc45c5994 (diff)
[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.
Diffstat (limited to 'include/linux/fs.h')
-rw-r--r--include/linux/fs.h1
1 files changed, 1 insertions, 0 deletions
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b424acbe1016..661e12c67875 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1136,6 +1136,7 @@ extern void vfs_caches_init(unsigned long);
extern int register_blkdev(unsigned int, const char *);
extern int unregister_blkdev(unsigned int, const char *);
extern struct block_device *bdget(dev_t);
+extern void bd_set_size(struct block_device *, loff_t size);
extern void bd_forget(struct inode *inode);
extern void bdput(struct block_device *);
extern int blkdev_open(struct inode *, struct file *);