aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-06-06 13:19:32 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-06-14 11:30:17 -0400
commit8c2a1a3028d560cfb95f1c583e872c65ed2f0b3d (patch)
tree05230bf96a4c0122d672ea41426b992442e71089 /fs/btrfs
parent01cd33674e95296e1647da3534b9aef1e98556b5 (diff)
Btrfs: exclude logged extents before replying when we are mixed
With non-mixed block groups we replay the logs before we're allowed to do any writes, so we get away with not pinning/removing the data extents until right when we replay them. However with mixed block groups we allocate out of the same pool, so we could easily allocate a metadata block that was logged in our tree log. To deal with this we just need to notice that we have mixed block groups and do the normal excluding/removal dance during the pin stage of the log replay and that way we don't allocate metadata blocks from areas we have logged data extents. With this patch we now pass xfstests generic/311 with mixed block groups turned on. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h2
-rw-r--r--fs/btrfs/extent-tree.c122
-rw-r--r--fs/btrfs/tree-log.c12
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);
3068int btrfs_pin_extent_for_log_replay(struct btrfs_root *root, 3068int btrfs_pin_extent_for_log_replay(struct btrfs_root *root,
3069 u64 bytenr, u64 num_bytes); 3069 u64 bytenr, u64 num_bytes);
3070int btrfs_exclude_logged_extents(struct btrfs_root *root,
3071 struct extent_buffer *eb);
3070int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans, 3072int 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
5217static 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 }
5254out_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
5262int 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 }
6621out_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);
6633out:
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)