diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 122 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 12 |
3 files changed, 99 insertions, 37 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 80ab1a6f4fe3..0049fe0f3f74 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -3067,6 +3067,8 @@ int btrfs_pin_extent(struct btrfs_root *root, | |||
3067 | u64 bytenr, u64 num, int reserved); | 3067 | u64 bytenr, u64 num, int reserved); |
3068 | int btrfs_pin_extent_for_log_replay(struct btrfs_root *root, | 3068 | int btrfs_pin_extent_for_log_replay(struct btrfs_root *root, |
3069 | u64 bytenr, u64 num_bytes); | 3069 | u64 bytenr, u64 num_bytes); |
3070 | int btrfs_exclude_logged_extents(struct btrfs_root *root, | ||
3071 | struct extent_buffer *eb); | ||
3070 | int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans, | 3072 | int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans, |
3071 | struct btrfs_root *root, | 3073 | struct btrfs_root *root, |
3072 | u64 objectid, u64 offset, u64 bytenr); | 3074 | u64 objectid, u64 offset, u64 bytenr); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index e14f8bd4b310..f84d53bc2f5d 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -5214,6 +5214,80 @@ int btrfs_pin_extent_for_log_replay(struct btrfs_root *root, | |||
5214 | return ret; | 5214 | return ret; |
5215 | } | 5215 | } |
5216 | 5216 | ||
5217 | static int __exclude_logged_extent(struct btrfs_root *root, u64 start, u64 num_bytes) | ||
5218 | { | ||
5219 | int ret; | ||
5220 | struct btrfs_block_group_cache *block_group; | ||
5221 | struct btrfs_caching_control *caching_ctl; | ||
5222 | |||
5223 | block_group = btrfs_lookup_block_group(root->fs_info, start); | ||
5224 | if (!block_group) | ||
5225 | return -EINVAL; | ||
5226 | |||
5227 | cache_block_group(block_group, 0); | ||
5228 | caching_ctl = get_caching_control(block_group); | ||
5229 | |||
5230 | if (!caching_ctl) { | ||
5231 | /* Logic error */ | ||
5232 | BUG_ON(!block_group_cache_done(block_group)); | ||
5233 | ret = btrfs_remove_free_space(block_group, start, num_bytes); | ||
5234 | } else { | ||
5235 | mutex_lock(&caching_ctl->mutex); | ||
5236 | |||
5237 | if (start >= caching_ctl->progress) { | ||
5238 | ret = add_excluded_extent(root, start, num_bytes); | ||
5239 | } else if (start + num_bytes <= caching_ctl->progress) { | ||
5240 | ret = btrfs_remove_free_space(block_group, | ||
5241 | start, num_bytes); | ||
5242 | } else { | ||
5243 | num_bytes = caching_ctl->progress - start; | ||
5244 | ret = btrfs_remove_free_space(block_group, | ||
5245 | start, num_bytes); | ||
5246 | if (ret) | ||
5247 | goto out_lock; | ||
5248 | |||
5249 | num_bytes = (start + num_bytes) - | ||
5250 | caching_ctl->progress; | ||
5251 | start = caching_ctl->progress; | ||
5252 | ret = add_excluded_extent(root, start, num_bytes); | ||
5253 | } | ||
5254 | out_lock: | ||
5255 | mutex_unlock(&caching_ctl->mutex); | ||
5256 | put_caching_control(caching_ctl); | ||
5257 | } | ||
5258 | btrfs_put_block_group(block_group); | ||
5259 | return ret; | ||
5260 | } | ||
5261 | |||
5262 | int btrfs_exclude_logged_extents(struct btrfs_root *log, | ||
5263 | struct extent_buffer *eb) | ||
5264 | { | ||
5265 | struct btrfs_file_extent_item *item; | ||
5266 | struct btrfs_key key; | ||
5267 | int found_type; | ||
5268 | int i; | ||
5269 | |||
5270 | if (!btrfs_fs_incompat(log->fs_info, MIXED_GROUPS)) | ||
5271 | return 0; | ||
5272 | |||
5273 | for (i = 0; i < btrfs_header_nritems(eb); i++) { | ||
5274 | btrfs_item_key_to_cpu(eb, &key, i); | ||
5275 | if (key.type != BTRFS_EXTENT_DATA_KEY) | ||
5276 | continue; | ||
5277 | item = btrfs_item_ptr(eb, i, struct btrfs_file_extent_item); | ||
5278 | found_type = btrfs_file_extent_type(eb, item); | ||
5279 | if (found_type == BTRFS_FILE_EXTENT_INLINE) | ||
5280 | continue; | ||
5281 | if (btrfs_file_extent_disk_bytenr(eb, item) == 0) | ||
5282 | continue; | ||
5283 | key.objectid = btrfs_file_extent_disk_bytenr(eb, item); | ||
5284 | key.offset = btrfs_file_extent_disk_num_bytes(eb, item); | ||
5285 | __exclude_logged_extent(log, key.objectid, key.offset); | ||
5286 | } | ||
5287 | |||
5288 | return 0; | ||
5289 | } | ||
5290 | |||
5217 | /** | 5291 | /** |
5218 | * btrfs_update_reserved_bytes - update the block_group and space info counters | 5292 | * btrfs_update_reserved_bytes - update the block_group and space info counters |
5219 | * @cache: The cache we are manipulating | 5293 | * @cache: The cache we are manipulating |
@@ -6585,52 +6659,26 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, | |||
6585 | { | 6659 | { |
6586 | int ret; | 6660 | int ret; |
6587 | struct btrfs_block_group_cache *block_group; | 6661 | struct btrfs_block_group_cache *block_group; |
6588 | struct btrfs_caching_control *caching_ctl; | ||
6589 | u64 start = ins->objectid; | ||
6590 | u64 num_bytes = ins->offset; | ||
6591 | |||
6592 | block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid); | ||
6593 | cache_block_group(block_group, 0); | ||
6594 | caching_ctl = get_caching_control(block_group); | ||
6595 | 6662 | ||
6596 | if (!caching_ctl) { | 6663 | /* |
6597 | BUG_ON(!block_group_cache_done(block_group)); | 6664 | * Mixed block groups will exclude before processing the log so we only |
6598 | ret = btrfs_remove_free_space(block_group, start, num_bytes); | 6665 | * need to do the exlude dance if this fs isn't mixed. |
6599 | if (ret) | 6666 | */ |
6600 | goto out; | 6667 | if (!btrfs_fs_incompat(root->fs_info, MIXED_GROUPS)) { |
6601 | } else { | 6668 | ret = __exclude_logged_extent(root, ins->objectid, ins->offset); |
6602 | mutex_lock(&caching_ctl->mutex); | ||
6603 | |||
6604 | if (start >= caching_ctl->progress) { | ||
6605 | ret = add_excluded_extent(root, start, num_bytes); | ||
6606 | } else if (start + num_bytes <= caching_ctl->progress) { | ||
6607 | ret = btrfs_remove_free_space(block_group, | ||
6608 | start, num_bytes); | ||
6609 | } else { | ||
6610 | num_bytes = caching_ctl->progress - start; | ||
6611 | ret = btrfs_remove_free_space(block_group, | ||
6612 | start, num_bytes); | ||
6613 | if (ret) | ||
6614 | goto out_lock; | ||
6615 | |||
6616 | start = caching_ctl->progress; | ||
6617 | num_bytes = ins->objectid + ins->offset - | ||
6618 | caching_ctl->progress; | ||
6619 | ret = add_excluded_extent(root, start, num_bytes); | ||
6620 | } | ||
6621 | out_lock: | ||
6622 | mutex_unlock(&caching_ctl->mutex); | ||
6623 | put_caching_control(caching_ctl); | ||
6624 | if (ret) | 6669 | if (ret) |
6625 | goto out; | 6670 | return ret; |
6626 | } | 6671 | } |
6627 | 6672 | ||
6673 | block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid); | ||
6674 | if (!block_group) | ||
6675 | return -EINVAL; | ||
6676 | |||
6628 | ret = btrfs_update_reserved_bytes(block_group, ins->offset, | 6677 | ret = btrfs_update_reserved_bytes(block_group, ins->offset, |
6629 | RESERVE_ALLOC_NO_ACCOUNT); | 6678 | RESERVE_ALLOC_NO_ACCOUNT); |
6630 | BUG_ON(ret); /* logic error */ | 6679 | BUG_ON(ret); /* logic error */ |
6631 | ret = alloc_reserved_file_extent(trans, root, 0, root_objectid, | 6680 | ret = alloc_reserved_file_extent(trans, root, 0, root_objectid, |
6632 | 0, owner, offset, ins, 1); | 6681 | 0, owner, offset, ins, 1); |
6633 | out: | ||
6634 | btrfs_put_block_group(block_group); | 6682 | btrfs_put_block_group(block_group); |
6635 | return ret; | 6683 | return ret; |
6636 | } | 6684 | } |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 831ddd4bf897..2c6791493637 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -280,11 +280,23 @@ static int process_one_buffer(struct btrfs_root *log, | |||
280 | { | 280 | { |
281 | int ret = 0; | 281 | int ret = 0; |
282 | 282 | ||
283 | /* | ||
284 | * If this fs is mixed then we need to be able to process the leaves to | ||
285 | * pin down any logged extents, so we have to read the block. | ||
286 | */ | ||
287 | if (btrfs_fs_incompat(log->fs_info, MIXED_GROUPS)) { | ||
288 | ret = btrfs_read_buffer(eb, gen); | ||
289 | if (ret) | ||
290 | return ret; | ||
291 | } | ||
292 | |||
283 | if (wc->pin) | 293 | if (wc->pin) |
284 | ret = btrfs_pin_extent_for_log_replay(log->fs_info->extent_root, | 294 | ret = btrfs_pin_extent_for_log_replay(log->fs_info->extent_root, |
285 | eb->start, eb->len); | 295 | eb->start, eb->len); |
286 | 296 | ||
287 | if (!ret && btrfs_buffer_uptodate(eb, gen, 0)) { | 297 | if (!ret && btrfs_buffer_uptodate(eb, gen, 0)) { |
298 | if (wc->pin && btrfs_header_level(eb) == 0) | ||
299 | ret = btrfs_exclude_logged_extents(log, eb); | ||
288 | if (wc->write) | 300 | if (wc->write) |
289 | btrfs_write_tree_block(eb); | 301 | btrfs_write_tree_block(eb); |
290 | if (wc->wait) | 302 | if (wc->wait) |