diff options
| -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 | } |
