diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 18abea802794..2b15daa3a9f2 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -236,6 +236,7 @@ static int wait_for_commit(struct btrfs_root *root, | |||
236 | struct dirty_root { | 236 | struct dirty_root { |
237 | struct list_head list; | 237 | struct list_head list; |
238 | struct btrfs_root *root; | 238 | struct btrfs_root *root; |
239 | struct btrfs_root *latest_root; | ||
239 | }; | 240 | }; |
240 | 241 | ||
241 | int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list) | 242 | int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list) |
@@ -278,6 +279,15 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
278 | btrfs_root_blocknr(&root->root_item)); | 279 | btrfs_root_blocknr(&root->root_item)); |
279 | brelse(root->commit_root); | 280 | brelse(root->commit_root); |
280 | root->commit_root = NULL; | 281 | root->commit_root = NULL; |
282 | |||
283 | /* make sure to update the root on disk | ||
284 | * so we get any updates to the block used | ||
285 | * counts | ||
286 | */ | ||
287 | err = btrfs_update_root(trans, | ||
288 | root->fs_info->tree_root, | ||
289 | &root->root_key, | ||
290 | &root->root_item); | ||
281 | continue; | 291 | continue; |
282 | } | 292 | } |
283 | dirty = kmalloc(sizeof(*dirty), GFP_NOFS); | 293 | dirty = kmalloc(sizeof(*dirty), GFP_NOFS); |
@@ -291,6 +301,7 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
291 | 301 | ||
292 | memcpy(dirty->root, root, sizeof(*root)); | 302 | memcpy(dirty->root, root, sizeof(*root)); |
293 | dirty->root->node = root->commit_root; | 303 | dirty->root->node = root->commit_root; |
304 | dirty->latest_root = root; | ||
294 | root->commit_root = NULL; | 305 | root->commit_root = NULL; |
295 | 306 | ||
296 | root->root_key.offset = root->fs_info->generation; | 307 | root->root_key.offset = root->fs_info->generation; |
@@ -384,20 +395,29 @@ static int drop_dirty_roots(struct btrfs_root *tree_root, | |||
384 | { | 395 | { |
385 | struct dirty_root *dirty; | 396 | struct dirty_root *dirty; |
386 | struct btrfs_trans_handle *trans; | 397 | struct btrfs_trans_handle *trans; |
398 | u64 num_blocks; | ||
399 | u64 blocks_used; | ||
387 | int ret = 0; | 400 | int ret = 0; |
388 | int err; | 401 | int err; |
389 | 402 | ||
390 | while(!list_empty(list)) { | 403 | while(!list_empty(list)) { |
404 | struct btrfs_root *root; | ||
405 | |||
391 | mutex_lock(&tree_root->fs_info->fs_mutex); | 406 | mutex_lock(&tree_root->fs_info->fs_mutex); |
392 | dirty = list_entry(list->next, struct dirty_root, list); | 407 | dirty = list_entry(list->next, struct dirty_root, list); |
393 | list_del_init(&dirty->list); | 408 | list_del_init(&dirty->list); |
394 | 409 | ||
410 | num_blocks = btrfs_root_blocks_used(&dirty->root->root_item); | ||
411 | root = dirty->latest_root; | ||
412 | |||
395 | while(1) { | 413 | while(1) { |
396 | trans = btrfs_start_transaction(tree_root, 1); | 414 | trans = btrfs_start_transaction(tree_root, 1); |
415 | |||
397 | ret = btrfs_drop_snapshot(trans, dirty->root); | 416 | ret = btrfs_drop_snapshot(trans, dirty->root); |
398 | if (ret != -EAGAIN) { | 417 | if (ret != -EAGAIN) { |
399 | break; | 418 | break; |
400 | } | 419 | } |
420 | |||
401 | err = btrfs_update_root(trans, | 421 | err = btrfs_update_root(trans, |
402 | tree_root, | 422 | tree_root, |
403 | &dirty->root->root_key, | 423 | &dirty->root->root_key, |
@@ -414,9 +434,19 @@ static int drop_dirty_roots(struct btrfs_root *tree_root, | |||
414 | mutex_lock(&tree_root->fs_info->fs_mutex); | 434 | mutex_lock(&tree_root->fs_info->fs_mutex); |
415 | } | 435 | } |
416 | BUG_ON(ret); | 436 | BUG_ON(ret); |
437 | |||
438 | num_blocks -= btrfs_root_blocks_used(&dirty->root->root_item); | ||
439 | blocks_used = btrfs_root_blocks_used(&root->root_item); | ||
440 | if (num_blocks) { | ||
441 | record_root_in_trans(root); | ||
442 | btrfs_set_root_blocks_used(&root->root_item, | ||
443 | blocks_used - num_blocks); | ||
444 | } | ||
417 | ret = btrfs_del_root(trans, tree_root, &dirty->root->root_key); | 445 | ret = btrfs_del_root(trans, tree_root, &dirty->root->root_key); |
418 | if (ret) | 446 | if (ret) { |
447 | BUG(); | ||
419 | break; | 448 | break; |
449 | } | ||
420 | ret = btrfs_end_transaction(trans, tree_root); | 450 | ret = btrfs_end_transaction(trans, tree_root); |
421 | BUG_ON(ret); | 451 | BUG_ON(ret); |
422 | 452 | ||
@@ -534,10 +564,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
534 | wake_up(&cur_trans->commit_wait); | 564 | wake_up(&cur_trans->commit_wait); |
535 | put_transaction(cur_trans); | 565 | put_transaction(cur_trans); |
536 | put_transaction(cur_trans); | 566 | put_transaction(cur_trans); |
567 | |||
537 | if (root->fs_info->closing) | 568 | if (root->fs_info->closing) |
538 | list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots); | 569 | list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots); |
539 | else | 570 | else |
540 | list_splice_init(&dirty_fs_roots, &root->fs_info->dead_roots); | 571 | list_splice_init(&dirty_fs_roots, &root->fs_info->dead_roots); |
572 | |||
541 | mutex_unlock(&root->fs_info->trans_mutex); | 573 | mutex_unlock(&root->fs_info->trans_mutex); |
542 | kmem_cache_free(btrfs_trans_handle_cachep, trans); | 574 | kmem_cache_free(btrfs_trans_handle_cachep, trans); |
543 | 575 | ||