diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-05-23 14:14:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-05-23 14:14:10 -0400 |
commit | 7ce14f6ff26460819345fe8495cf2dd6538b7cdc (patch) | |
tree | 23fb69457c5f2c3b80aebf2a7351b57d87426c6d /fs | |
parent | cf539cbd8a81e12880735a0912de8b99f46c84fd (diff) | |
parent | 153c35b6cccc0c72de9fae06c8e2c8b2c47d79d4 (diff) |
Merge branch 'for-linus-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull btrfs fixes from Chris Mason:
"I fixed up a regression from 4.0 where conversion between different
raid levels would sometimes bail out without converting.
Filipe tracked down a race where it was possible to double allocate
chunks on the drive.
Mark has a fix for fiemap. All three will get bundled off for stable
as well"
* 'for-linus-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
Btrfs: fix regression in raid level conversion
Btrfs: fix racy system chunk allocation when setting block group ro
btrfs: clear 'ret' in btrfs_check_shared() loop
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/backref.c | 17 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 20 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 1 |
3 files changed, 38 insertions, 0 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 9de772ee0031..614aaa1969bd 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c | |||
@@ -880,6 +880,8 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info, | |||
880 | * indirect refs to their parent bytenr. | 880 | * indirect refs to their parent bytenr. |
881 | * When roots are found, they're added to the roots list | 881 | * When roots are found, they're added to the roots list |
882 | * | 882 | * |
883 | * NOTE: This can return values > 0 | ||
884 | * | ||
883 | * FIXME some caching might speed things up | 885 | * FIXME some caching might speed things up |
884 | */ | 886 | */ |
885 | static int find_parent_nodes(struct btrfs_trans_handle *trans, | 887 | static int find_parent_nodes(struct btrfs_trans_handle *trans, |
@@ -1198,6 +1200,19 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans, | |||
1198 | return ret; | 1200 | return ret; |
1199 | } | 1201 | } |
1200 | 1202 | ||
1203 | /** | ||
1204 | * btrfs_check_shared - tell us whether an extent is shared | ||
1205 | * | ||
1206 | * @trans: optional trans handle | ||
1207 | * | ||
1208 | * btrfs_check_shared uses the backref walking code but will short | ||
1209 | * circuit as soon as it finds a root or inode that doesn't match the | ||
1210 | * one passed in. This provides a significant performance benefit for | ||
1211 | * callers (such as fiemap) which want to know whether the extent is | ||
1212 | * shared but do not need a ref count. | ||
1213 | * | ||
1214 | * Return: 0 if extent is not shared, 1 if it is shared, < 0 on error. | ||
1215 | */ | ||
1201 | int btrfs_check_shared(struct btrfs_trans_handle *trans, | 1216 | int btrfs_check_shared(struct btrfs_trans_handle *trans, |
1202 | struct btrfs_fs_info *fs_info, u64 root_objectid, | 1217 | struct btrfs_fs_info *fs_info, u64 root_objectid, |
1203 | u64 inum, u64 bytenr) | 1218 | u64 inum, u64 bytenr) |
@@ -1226,11 +1241,13 @@ int btrfs_check_shared(struct btrfs_trans_handle *trans, | |||
1226 | ret = find_parent_nodes(trans, fs_info, bytenr, elem.seq, tmp, | 1241 | ret = find_parent_nodes(trans, fs_info, bytenr, elem.seq, tmp, |
1227 | roots, NULL, root_objectid, inum); | 1242 | roots, NULL, root_objectid, inum); |
1228 | if (ret == BACKREF_FOUND_SHARED) { | 1243 | if (ret == BACKREF_FOUND_SHARED) { |
1244 | /* this is the only condition under which we return 1 */ | ||
1229 | ret = 1; | 1245 | ret = 1; |
1230 | break; | 1246 | break; |
1231 | } | 1247 | } |
1232 | if (ret < 0 && ret != -ENOENT) | 1248 | if (ret < 0 && ret != -ENOENT) |
1233 | break; | 1249 | break; |
1250 | ret = 0; | ||
1234 | node = ulist_next(tmp, &uiter); | 1251 | node = ulist_next(tmp, &uiter); |
1235 | if (!node) | 1252 | if (!node) |
1236 | break; | 1253 | break; |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 7effed6f2fa6..0ec3acd14cbf 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -8829,6 +8829,24 @@ again: | |||
8829 | goto again; | 8829 | goto again; |
8830 | } | 8830 | } |
8831 | 8831 | ||
8832 | /* | ||
8833 | * if we are changing raid levels, try to allocate a corresponding | ||
8834 | * block group with the new raid level. | ||
8835 | */ | ||
8836 | alloc_flags = update_block_group_flags(root, cache->flags); | ||
8837 | if (alloc_flags != cache->flags) { | ||
8838 | ret = do_chunk_alloc(trans, root, alloc_flags, | ||
8839 | CHUNK_ALLOC_FORCE); | ||
8840 | /* | ||
8841 | * ENOSPC is allowed here, we may have enough space | ||
8842 | * already allocated at the new raid level to | ||
8843 | * carry on | ||
8844 | */ | ||
8845 | if (ret == -ENOSPC) | ||
8846 | ret = 0; | ||
8847 | if (ret < 0) | ||
8848 | goto out; | ||
8849 | } | ||
8832 | 8850 | ||
8833 | ret = set_block_group_ro(cache, 0); | 8851 | ret = set_block_group_ro(cache, 0); |
8834 | if (!ret) | 8852 | if (!ret) |
@@ -8842,7 +8860,9 @@ again: | |||
8842 | out: | 8860 | out: |
8843 | if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) { | 8861 | if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) { |
8844 | alloc_flags = update_block_group_flags(root, cache->flags); | 8862 | alloc_flags = update_block_group_flags(root, cache->flags); |
8863 | lock_chunks(root->fs_info->chunk_root); | ||
8845 | check_system_chunk(trans, root, alloc_flags); | 8864 | check_system_chunk(trans, root, alloc_flags); |
8865 | unlock_chunks(root->fs_info->chunk_root); | ||
8846 | } | 8866 | } |
8847 | mutex_unlock(&root->fs_info->ro_block_group_mutex); | 8867 | mutex_unlock(&root->fs_info->ro_block_group_mutex); |
8848 | 8868 | ||
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 96aebf3bcd5b..174f5e1e00ab 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -4625,6 +4625,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
4625 | { | 4625 | { |
4626 | u64 chunk_offset; | 4626 | u64 chunk_offset; |
4627 | 4627 | ||
4628 | ASSERT(mutex_is_locked(&extent_root->fs_info->chunk_mutex)); | ||
4628 | chunk_offset = find_next_chunk(extent_root->fs_info); | 4629 | chunk_offset = find_next_chunk(extent_root->fs_info); |
4629 | return __btrfs_alloc_chunk(trans, extent_root, chunk_offset, type); | 4630 | return __btrfs_alloc_chunk(trans, extent_root, chunk_offset, type); |
4630 | } | 4631 | } |