lkml.org 
[lkml]   [2005]   [Mar]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH] blockdev: fixes race between mount/umount
This patch fixes a race between mount and umount in set_blocksize. The results
can vary between buffer errors and infinite loops in __getblk_slow, and
possibly others.

The patch makes set_blocksize run under the bdev_lock if it is the sole holder
of the block device.

Changes:
- Added missing sync_blockdev in kill_block_super, lost in the shuffle.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>

diff -ruNpX dontdiff linux-2.6.11-rc4.orig/fs/block_dev.c linux-2.6.11-rc4/fs/block_dev.c
--- linux-2.6.11-rc4.orig/fs/block_dev.c 2005-02-28 14:06:59.000000000 -0500
+++ linux-2.6.11-rc4/fs/block_dev.c 2005-02-28 14:49:52.000000000 -0500
@@ -62,7 +62,7 @@ static void kill_bdev(struct block_devic
truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
}

-int set_blocksize(struct block_device *bdev, int size)
+int __set_blocksize(struct block_device *bdev, int size, int sync)
{
/* Size must be a power of two, and between 512 and PAGE_SIZE */
if (size > PAGE_SIZE || size < 512 || (size & (size-1)))
@@ -74,7 +74,8 @@ int set_blocksize(struct block_device *b

/* Don't change the size if it is same as current */
if (bdev->bd_block_size != size) {
- sync_blockdev(bdev);
+ if (sync)
+ sync_blockdev(bdev);
bdev->bd_block_size = size;
bdev->bd_inode->i_blkbits = blksize_bits(size);
kill_bdev(bdev);
@@ -82,7 +83,7 @@ int set_blocksize(struct block_device *b
return 0;
}

-EXPORT_SYMBOL(set_blocksize);
+EXPORT_SYMBOL(__set_blocksize);

int sb_set_blocksize(struct super_block *sb, int size)
{
@@ -480,17 +481,19 @@ int bd_claim(struct block_device *bdev,

EXPORT_SYMBOL(bd_claim);

-void bd_release(struct block_device *bdev)
+void __bd_release(struct block_device *bdev, int size)
{
spin_lock(&bdev_lock);
if (!--bdev->bd_contains->bd_holders)
bdev->bd_contains->bd_holder = NULL;
- if (!--bdev->bd_holders)
+ if (!--bdev->bd_holders) {
bdev->bd_holder = NULL;
+ set_blocksize_nosync (bdev, size);
+ }
spin_unlock(&bdev_lock);
}

-EXPORT_SYMBOL(bd_release);
+EXPORT_SYMBOL(__bd_release);

/*
* Tries to open block device by device number. Use it ONLY if you
@@ -914,10 +917,10 @@ EXPORT_SYMBOL(open_bdev_excl);
*
* This is the counterpart to open_bdev_excl().
*/
-void close_bdev_excl(struct block_device *bdev)
+void __close_bdev_excl(struct block_device *bdev, int size)
{
- bd_release(bdev);
+ __bd_release(bdev, size);
blkdev_put(bdev);
}

-EXPORT_SYMBOL(close_bdev_excl);
+EXPORT_SYMBOL(__close_bdev_excl);
diff -ruNpX dontdiff linux-2.6.11-rc4.orig/fs/super.c linux-2.6.11-rc4/fs/super.c
--- linux-2.6.11-rc4.orig/fs/super.c 2005-02-28 14:07:01.000000000 -0500
+++ linux-2.6.11-rc4/fs/super.c 2005-02-28 14:42:49.000000000 -0500
@@ -732,8 +732,8 @@ void kill_block_super(struct super_block

bdev_uevent(bdev, KOBJ_UMOUNT);
generic_shutdown_super(sb);
- set_blocksize(bdev, sb->s_old_blocksize);
- close_bdev_excl(bdev);
+ sync_blockdev(bdev);
+ __close_bdev_excl(bdev, sb->s_old_blocksize);
}

EXPORT_SYMBOL(kill_block_super);
diff -ruNpX dontdiff linux-2.6.11-rc4.orig/include/linux/fs.h linux-2.6.11-rc4/include/linux/fs.h
--- linux-2.6.11-rc4.orig/include/linux/fs.h 2005-02-28 14:07:42.000000000 -0500
+++ linux-2.6.11-rc4/include/linux/fs.h 2005-02-28 14:50:53.000000000 -0500
@@ -1294,7 +1294,10 @@ extern long compat_blkdev_ioctl(struct f
extern int blkdev_get(struct block_device *, mode_t, unsigned);
extern int blkdev_put(struct block_device *);
extern int bd_claim(struct block_device *, void *);
-extern void bd_release(struct block_device *);
+extern void __bd_release(struct block_device *, int);
+static inline void bd_release(struct block_device *bdev) {
+ __bd_release (bdev, bdev->bd_block_size);
+}

/* fs/char_dev.c */
extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);
@@ -1311,7 +1314,10 @@ extern const char *__bdevname(dev_t, cha
extern const char *bdevname(struct block_device *bdev, char *buffer);
extern struct block_device *lookup_bdev(const char *);
extern struct block_device *open_bdev_excl(const char *, int, void *);
-extern void close_bdev_excl(struct block_device *);
+extern void __close_bdev_excl(struct block_device *, int);
+static inline void close_bdev_excl(struct block_device *bdev) {
+ __close_bdev_excl(bdev, bdev->bd_block_size);
+}

extern void init_special_inode(struct inode *, umode_t, dev_t);

@@ -1447,7 +1453,14 @@ extern void file_kill(struct file *f);
struct bio;
extern void submit_bio(int, struct bio *);
extern int bdev_read_only(struct block_device *);
-extern int set_blocksize(struct block_device *, int);
+extern int __set_blocksize(struct block_device *, int, int);
+static inline int set_blocksize(struct block_device *bdev, int size) {
+ return __set_blocksize (bdev, size, 1);
+}
+static inline int set_blocksize_nosync(struct block_device *bdev, int size) {
+ return __set_blocksize (bdev, size, 0);
+}
+
extern int sb_set_blocksize(struct super_block *, int);
extern int sb_min_blocksize(struct super_block *, int);

--
Jeff Mahoney
SuSE Labs
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
\
 
 \ /
  Last update: 2005-03-22 14:10    [W:2.167 / U:0.064 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site