diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 106 |
1 files changed, 96 insertions, 10 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index d31a0c4f56be..e935035ac034 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); |
@@ -4469,7 +4485,8 @@ static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans, | |||
4469 | static int btrfs_check_ref_name_override(struct extent_buffer *eb, | 4485 | static int btrfs_check_ref_name_override(struct extent_buffer *eb, |
4470 | const int slot, | 4486 | const int slot, |
4471 | const struct btrfs_key *key, | 4487 | const struct btrfs_key *key, |
4472 | struct inode *inode) | 4488 | struct inode *inode, |
4489 | u64 *other_ino) | ||
4473 | { | 4490 | { |
4474 | int ret; | 4491 | int ret; |
4475 | struct btrfs_path *search_path; | 4492 | struct btrfs_path *search_path; |
@@ -4528,7 +4545,16 @@ static int btrfs_check_ref_name_override(struct extent_buffer *eb, | |||
4528 | search_path, parent, | 4545 | search_path, parent, |
4529 | name, this_name_len, 0); | 4546 | name, this_name_len, 0); |
4530 | if (di && !IS_ERR(di)) { | 4547 | if (di && !IS_ERR(di)) { |
4531 | ret = 1; | 4548 | struct btrfs_key di_key; |
4549 | |||
4550 | btrfs_dir_item_key_to_cpu(search_path->nodes[0], | ||
4551 | di, &di_key); | ||
4552 | if (di_key.type == BTRFS_INODE_ITEM_KEY) { | ||
4553 | ret = 1; | ||
4554 | *other_ino = di_key.objectid; | ||
4555 | } else { | ||
4556 | ret = -EAGAIN; | ||
4557 | } | ||
4532 | goto out; | 4558 | goto out; |
4533 | } else if (IS_ERR(di)) { | 4559 | } else if (IS_ERR(di)) { |
4534 | ret = PTR_ERR(di); | 4560 | ret = PTR_ERR(di); |
@@ -4722,16 +4748,72 @@ again: | |||
4722 | if ((min_key.type == BTRFS_INODE_REF_KEY || | 4748 | if ((min_key.type == BTRFS_INODE_REF_KEY || |
4723 | min_key.type == BTRFS_INODE_EXTREF_KEY) && | 4749 | min_key.type == BTRFS_INODE_EXTREF_KEY) && |
4724 | BTRFS_I(inode)->generation == trans->transid) { | 4750 | BTRFS_I(inode)->generation == trans->transid) { |
4751 | u64 other_ino = 0; | ||
4752 | |||
4725 | ret = btrfs_check_ref_name_override(path->nodes[0], | 4753 | ret = btrfs_check_ref_name_override(path->nodes[0], |
4726 | path->slots[0], | 4754 | path->slots[0], |
4727 | &min_key, inode); | 4755 | &min_key, inode, |
4756 | &other_ino); | ||
4728 | if (ret < 0) { | 4757 | if (ret < 0) { |
4729 | err = ret; | 4758 | err = ret; |
4730 | goto out_unlock; | 4759 | goto out_unlock; |
4731 | } else if (ret > 0) { | 4760 | } else if (ret > 0 && ctx && |
4732 | err = 1; | 4761 | other_ino != btrfs_ino(ctx->inode)) { |
4733 | btrfs_set_log_full_commit(root->fs_info, trans); | 4762 | struct btrfs_key inode_key; |
4734 | goto out_unlock; | 4763 | struct inode *other_inode; |
4764 | |||
4765 | if (ins_nr > 0) { | ||
4766 | ins_nr++; | ||
4767 | } else { | ||
4768 | ins_nr = 1; | ||
4769 | ins_start_slot = path->slots[0]; | ||
4770 | } | ||
4771 | ret = copy_items(trans, inode, dst_path, path, | ||
4772 | &last_extent, ins_start_slot, | ||
4773 | ins_nr, inode_only, | ||
4774 | logged_isize); | ||
4775 | if (ret < 0) { | ||
4776 | err = ret; | ||
4777 | goto out_unlock; | ||
4778 | } | ||
4779 | ins_nr = 0; | ||
4780 | btrfs_release_path(path); | ||
4781 | inode_key.objectid = other_ino; | ||
4782 | inode_key.type = BTRFS_INODE_ITEM_KEY; | ||
4783 | inode_key.offset = 0; | ||
4784 | other_inode = btrfs_iget(root->fs_info->sb, | ||
4785 | &inode_key, root, | ||
4786 | NULL); | ||
4787 | /* | ||
4788 | * If the other inode that had a conflicting dir | ||
4789 | * entry was deleted in the current transaction, | ||
4790 | * we don't need to do more work nor fallback to | ||
4791 | * a transaction commit. | ||
4792 | */ | ||
4793 | if (IS_ERR(other_inode) && | ||
4794 | PTR_ERR(other_inode) == -ENOENT) { | ||
4795 | goto next_key; | ||
4796 | } else if (IS_ERR(other_inode)) { | ||
4797 | err = PTR_ERR(other_inode); | ||
4798 | goto out_unlock; | ||
4799 | } | ||
4800 | /* | ||
4801 | * We are safe logging the other inode without | ||
4802 | * acquiring its i_mutex as long as we log with | ||
4803 | * the LOG_INODE_EXISTS mode. We're safe against | ||
4804 | * concurrent renames of the other inode as well | ||
4805 | * because during a rename we pin the log and | ||
4806 | * update the log with the new name before we | ||
4807 | * unpin it. | ||
4808 | */ | ||
4809 | err = btrfs_log_inode(trans, root, other_inode, | ||
4810 | LOG_INODE_EXISTS, | ||
4811 | 0, LLONG_MAX, ctx); | ||
4812 | iput(other_inode); | ||
4813 | if (err) | ||
4814 | goto out_unlock; | ||
4815 | else | ||
4816 | goto next_key; | ||
4735 | } | 4817 | } |
4736 | } | 4818 | } |
4737 | 4819 | ||
@@ -4799,7 +4881,7 @@ next_slot: | |||
4799 | ins_nr = 0; | 4881 | ins_nr = 0; |
4800 | } | 4882 | } |
4801 | btrfs_release_path(path); | 4883 | btrfs_release_path(path); |
4802 | 4884 | next_key: | |
4803 | if (min_key.offset < (u64)-1) { | 4885 | if (min_key.offset < (u64)-1) { |
4804 | min_key.offset++; | 4886 | min_key.offset++; |
4805 | } else if (min_key.type < max_key.type) { | 4887 | } else if (min_key.type < max_key.type) { |
@@ -4993,8 +5075,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) | 5075 | if (!parent || d_really_is_negative(parent) || sb != parent->d_sb) |
4994 | break; | 5076 | break; |
4995 | 5077 | ||
4996 | if (IS_ROOT(parent)) | 5078 | if (IS_ROOT(parent)) { |
5079 | inode = d_inode(parent); | ||
5080 | if (btrfs_must_commit_transaction(trans, inode)) | ||
5081 | ret = 1; | ||
4997 | break; | 5082 | break; |
5083 | } | ||
4998 | 5084 | ||
4999 | parent = dget_parent(parent); | 5085 | parent = dget_parent(parent); |
5000 | dput(old_parent); | 5086 | dput(old_parent); |