diff options
author | Chris Mason <chris.mason@oracle.com> | 2009-06-10 15:17:02 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-06-10 15:17:02 -0400 |
commit | e5e9a5206a171b2c467e494aebcdcf70c47289bc (patch) | |
tree | d9a6a89cccbd084db923f1661b52d5a1dfdb83fe /fs/btrfs/disk-io.c | |
parent | 7df336ec1266dccbb253bac52c529d3dcc7c22d0 (diff) |
Btrfs: avoid races between super writeout and device list updates
On multi-device filesystems, btrfs writes supers to all of the devices
before considering a sync complete. There wasn't any additional
locking between super writeout and the device list management code
because device management was done inside a transaction and
super writeout only happened with no transation writers running.
With the btrfs fsync log and other async transaction updates, this
has been racey for some time. This adds a mutex to protect
the device list. The existing volume mutex could not be reused due to
transaction lock ordering requirements.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 6c54c210dfd0..b7ddc77fa568 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -2111,7 +2111,7 @@ static int write_dev_supers(struct btrfs_device *device, | |||
2111 | 2111 | ||
2112 | int write_all_supers(struct btrfs_root *root, int max_mirrors) | 2112 | int write_all_supers(struct btrfs_root *root, int max_mirrors) |
2113 | { | 2113 | { |
2114 | struct list_head *head = &root->fs_info->fs_devices->devices; | 2114 | struct list_head *head; |
2115 | struct btrfs_device *dev; | 2115 | struct btrfs_device *dev; |
2116 | struct btrfs_super_block *sb; | 2116 | struct btrfs_super_block *sb; |
2117 | struct btrfs_dev_item *dev_item; | 2117 | struct btrfs_dev_item *dev_item; |
@@ -2126,6 +2126,9 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors) | |||
2126 | 2126 | ||
2127 | sb = &root->fs_info->super_for_commit; | 2127 | sb = &root->fs_info->super_for_commit; |
2128 | dev_item = &sb->dev_item; | 2128 | dev_item = &sb->dev_item; |
2129 | |||
2130 | mutex_lock(&root->fs_info->fs_devices->device_list_mutex); | ||
2131 | head = &root->fs_info->fs_devices->devices; | ||
2129 | list_for_each_entry(dev, head, dev_list) { | 2132 | list_for_each_entry(dev, head, dev_list) { |
2130 | if (!dev->bdev) { | 2133 | if (!dev->bdev) { |
2131 | total_errors++; | 2134 | total_errors++; |
@@ -2169,6 +2172,7 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors) | |||
2169 | if (ret) | 2172 | if (ret) |
2170 | total_errors++; | 2173 | total_errors++; |
2171 | } | 2174 | } |
2175 | mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); | ||
2172 | if (total_errors > max_errors) { | 2176 | if (total_errors > max_errors) { |
2173 | printk(KERN_ERR "btrfs: %d errors while writing supers\n", | 2177 | printk(KERN_ERR "btrfs: %d errors while writing supers\n", |
2174 | total_errors); | 2178 | total_errors); |