diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 107 |
1 files changed, 97 insertions, 10 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index d31a0c4f56be..ef9c55bc7907 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "backref.h" | 27 | #include "backref.h" |
28 | #include "hash.h" | 28 | #include "hash.h" |
29 | #include "compression.h" | 29 | #include "compression.h" |
30 | #include "qgroup.h" | ||
30 | 31 | ||
31 | /* magic values for the inode_only field in btrfs_log_inode: | 32 | /* magic values for the inode_only field in btrfs_log_inode: |
32 | * | 33 | * |
@@ -680,6 +681,21 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | |||
680 | ins.type = BTRFS_EXTENT_ITEM_KEY; | 681 | ins.type = BTRFS_EXTENT_ITEM_KEY; |
681 | offset = key->offset - btrfs_file_extent_offset(eb, item); | 682 | offset = key->offset - btrfs_file_extent_offset(eb, item); |
682 | 683 | ||
684 | /* | ||
685 | * Manually record dirty extent, as here we did a shallow | ||
686 | * file extent item copy and skip normal backref update, | ||
687 | * but modifying extent tree all by ourselves. | ||
688 | * So need to manually record dirty extent for qgroup, | ||
689 | * as the owner of the file extent changed from log tree | ||
690 | * (doesn't affect qgroup) to fs/file tree(affects qgroup) | ||
691 | */ | ||
692 | ret = btrfs_qgroup_insert_dirty_extent(trans, root->fs_info, | ||
693 | btrfs_file_extent_disk_bytenr(eb, item), | ||
694 | btrfs_file_extent_disk_num_bytes(eb, item), | ||
695 | GFP_NOFS); | ||
696 | if (ret < 0) | ||
697 | goto out; | ||
698 | |||
683 | if (ins.objectid > 0) { | 699 | if (ins.objectid > 0) { |
684 | u64 csum_start; | 700 | u64 csum_start; |
685 | u64 csum_end; | 701 | u64 csum_end; |
@@ -2807,7 +2823,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2807 | */ | 2823 | */ |
2808 | mutex_unlock(&root->log_mutex); | 2824 | mutex_unlock(&root->log_mutex); |
2809 | 2825 | ||
2810 | btrfs_init_log_ctx(&root_log_ctx); | 2826 | btrfs_init_log_ctx(&root_log_ctx, NULL); |
2811 | 2827 | ||
2812 | mutex_lock(&log_root_tree->log_mutex); | 2828 | mutex_lock(&log_root_tree->log_mutex); |
2813 | atomic_inc(&log_root_tree->log_batch); | 2829 | atomic_inc(&log_root_tree->log_batch); |
@@ -2851,6 +2867,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2851 | 2867 | ||
2852 | if (log_root_tree->log_transid_committed >= root_log_ctx.log_transid) { | 2868 | if (log_root_tree->log_transid_committed >= root_log_ctx.log_transid) { |
2853 | blk_finish_plug(&plug); | 2869 | blk_finish_plug(&plug); |
2870 | list_del_init(&root_log_ctx.list); | ||
2854 | mutex_unlock(&log_root_tree->log_mutex); | 2871 | mutex_unlock(&log_root_tree->log_mutex); |
2855 | ret = root_log_ctx.log_ret; | 2872 | ret = root_log_ctx.log_ret; |
2856 | goto out; | 2873 | goto out; |
@@ -4469,7 +4486,8 @@ static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans, | |||
4469 | static int btrfs_check_ref_name_override(struct extent_buffer *eb, | 4486 | static int btrfs_check_ref_name_override(struct extent_buffer *eb, |
4470 | const int slot, | 4487 | const int slot, |
4471 | const struct btrfs_key *key, | 4488 | const struct btrfs_key *key, |
4472 | struct inode *inode) | 4489 | struct inode *inode, |
4490 | u64 *other_ino) | ||
4473 | { | 4491 | { |
4474 | int ret; | 4492 | int ret; |
4475 | struct btrfs_path *search_path; | 4493 | struct btrfs_path *search_path; |
@@ -4528,7 +4546,16 @@ static int btrfs_check_ref_name_override(struct extent_buffer *eb, | |||
4528 | search_path, parent, | 4546 | search_path, parent, |
4529 | name, this_name_len, 0); | 4547 | name, this_name_len, 0); |
4530 | if (di && !IS_ERR(di)) { | 4548 | if (di && !IS_ERR(di)) { |
4531 | ret = 1; | 4549 | struct btrfs_key di_key; |
4550 | |||
4551 | btrfs_dir_item_key_to_cpu(search_path->nodes[0], | ||
4552 | di, &di_key); | ||
4553 | if (di_key.type == BTRFS_INODE_ITEM_KEY) { | ||
4554 | ret = 1; | ||
4555 | *other_ino = di_key.objectid; | ||
4556 | } else { | ||
4557 | ret = -EAGAIN; | ||
4558 | } | ||
4532 | goto out; | 4559 | goto out; |
4533 | } else if (IS_ERR(di)) { | 4560 | } else if (IS_ERR(di)) { |
4534 | ret = PTR_ERR(di); | 4561 | ret = PTR_ERR(di); |
@@ -4722,16 +4749,72 @@ again: | |||
4722 | if ((min_key.type == BTRFS_INODE_REF_KEY || | 4749 | if ((min_key.type == BTRFS_INODE_REF_KEY || |
4723 | min_key.type == BTRFS_INODE_EXTREF_KEY) && | 4750 | min_key.type == BTRFS_INODE_EXTREF_KEY) && |
4724 | BTRFS_I(inode)->generation == trans->transid) { | 4751 | BTRFS_I(inode)->generation == trans->transid) { |
4752 | u64 other_ino = 0; | ||
4753 | |||
4725 | ret = btrfs_check_ref_name_override(path->nodes[0], | 4754 | ret = btrfs_check_ref_name_override(path->nodes[0], |
4726 | path->slots[0], | 4755 | path->slots[0], |
4727 | &min_key, inode); | 4756 | &min_key, inode, |
4757 | &other_ino); | ||
4728 | if (ret < 0) { | 4758 | if (ret < 0) { |
4729 | err = ret; | 4759 | err = ret; |
4730 | goto out_unlock; | 4760 | goto out_unlock; |
4731 | } else if (ret > 0) { | 4761 | } else if (ret > 0 && ctx && |
4732 | err = 1; | 4762 | other_ino != btrfs_ino(ctx->inode)) { |
4733 | btrfs_set_log_full_commit(root->fs_info, trans); | 4763 | struct btrfs_key inode_key; |
4734 | goto out_unlock; | 4764 | struct inode *other_inode; |
4765 | |||
4766 | if (ins_nr > 0) { | ||
4767 | ins_nr++; | ||
4768 | } else { | ||
4769 | ins_nr = 1; | ||
4770 | ins_start_slot = path->slots[0]; | ||
4771 | } | ||
4772 | ret = copy_items(trans, inode, dst_path, path, | ||
4773 | &last_extent, ins_start_slot, | ||
4774 | ins_nr, inode_only, | ||
4775 | logged_isize); | ||
4776 | if (ret < 0) { | ||
4777 | err = ret; | ||
4778 | goto out_unlock; | ||
4779 | } | ||
4780 | ins_nr = 0; | ||
4781 | btrfs_release_path(path); | ||
4782 | inode_key.objectid = other_ino; | ||
4783 | inode_key.type = BTRFS_INODE_ITEM_KEY; | ||
4784 | inode_key.offset = 0; | ||
4785 | other_inode = btrfs_iget(root->fs_info->sb, | ||
4786 | &inode_key, root, | ||
4787 | NULL); | ||
4788 | /* | ||
4789 | * If the other inode that had a conflicting dir | ||
4790 | * entry was deleted in the current transaction, | ||
4791 | * we don't need to do more work nor fallback to | ||
4792 | * a transaction commit. | ||
4793 | */ | ||
4794 | if (IS_ERR(other_inode) && | ||
4795 | PTR_ERR(other_inode) == -ENOENT) { | ||
4796 | goto next_key; | ||
4797 | } else if (IS_ERR(other_inode)) { | ||
4798 | err = PTR_ERR(other_inode); | ||
4799 | goto out_unlock; | ||
4800 | } | ||
4801 | /* | ||
4802 | * We are safe logging the other inode without | ||
4803 | * acquiring its i_mutex as long as we log with | ||
4804 | * the LOG_INODE_EXISTS mode. We're safe against | ||
4805 | * concurrent renames of the other inode as well | ||
4806 | * because during a rename we pin the log and | ||
4807 | * update the log with the new name before we | ||
4808 | * unpin it. | ||
4809 | */ | ||
4810 | err = btrfs_log_inode(trans, root, other_inode, | ||
4811 | LOG_INODE_EXISTS, | ||
4812 | 0, LLONG_MAX, ctx); | ||
4813 | iput(other_inode); | ||
4814 | if (err) | ||
4815 | goto out_unlock; | ||
4816 | else | ||
4817 | goto next_key; | ||
4735 | } | 4818 | } |
4736 | } | 4819 | } |
4737 | 4820 | ||
@@ -4799,7 +4882,7 @@ next_slot: | |||
4799 | ins_nr = 0; | 4882 | ins_nr = 0; |
4800 | } | 4883 | } |
4801 | btrfs_release_path(path); | 4884 | btrfs_release_path(path); |
4802 | 4885 | next_key: | |
4803 | if (min_key.offset < (u64)-1) { | 4886 | if (min_key.offset < (u64)-1) { |
4804 | min_key.offset++; | 4887 | min_key.offset++; |
4805 | } else if (min_key.type < max_key.type) { | 4888 | } else if (min_key.type < max_key.type) { |
@@ -4993,8 +5076,12 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans, | |||
4993 | if (!parent || d_really_is_negative(parent) || sb != parent->d_sb) | 5076 | if (!parent || d_really_is_negative(parent) || sb != parent->d_sb) |
4994 | break; | 5077 | break; |
4995 | 5078 | ||
4996 | if (IS_ROOT(parent)) | 5079 | if (IS_ROOT(parent)) { |
5080 | inode = d_inode(parent); | ||
5081 | if (btrfs_must_commit_transaction(trans, inode)) | ||
5082 | ret = 1; | ||
4997 | break; | 5083 | break; |
5084 | } | ||
4998 | 5085 | ||
4999 | parent = dget_parent(parent); | 5086 | parent = dget_parent(parent); |
5000 | dput(old_parent); | 5087 | dput(old_parent); |