diff options
author | Chris Mason <clm@fb.com> | 2016-08-05 15:25:05 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2016-08-05 15:25:05 -0400 |
commit | 10838816547a28696ca10e038b3b32f2efec5a42 (patch) | |
tree | c8abb5cb6139473ea58859f2093a37d8328ee7bb /fs/btrfs/tree-log.c | |
parent | 42049bf60db4c01e0432fc861463dcd3208c0d93 (diff) | |
parent | e6571499336e10f93a77c51a35fd1a96828eea71 (diff) |
Merge branch 'integration-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/fdmanana/linux into for-linus-4.8
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 85 |
1 files changed, 77 insertions, 8 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index d31a0c4f56be..fff3f3efa436 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -4469,7 +4469,8 @@ static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans, | |||
4469 | static int btrfs_check_ref_name_override(struct extent_buffer *eb, | 4469 | static int btrfs_check_ref_name_override(struct extent_buffer *eb, |
4470 | const int slot, | 4470 | const int slot, |
4471 | const struct btrfs_key *key, | 4471 | const struct btrfs_key *key, |
4472 | struct inode *inode) | 4472 | struct inode *inode, |
4473 | u64 *other_ino) | ||
4473 | { | 4474 | { |
4474 | int ret; | 4475 | int ret; |
4475 | struct btrfs_path *search_path; | 4476 | struct btrfs_path *search_path; |
@@ -4528,7 +4529,16 @@ static int btrfs_check_ref_name_override(struct extent_buffer *eb, | |||
4528 | search_path, parent, | 4529 | search_path, parent, |
4529 | name, this_name_len, 0); | 4530 | name, this_name_len, 0); |
4530 | if (di && !IS_ERR(di)) { | 4531 | if (di && !IS_ERR(di)) { |
4531 | ret = 1; | 4532 | struct btrfs_key di_key; |
4533 | |||
4534 | btrfs_dir_item_key_to_cpu(search_path->nodes[0], | ||
4535 | di, &di_key); | ||
4536 | if (di_key.type == BTRFS_INODE_ITEM_KEY) { | ||
4537 | ret = 1; | ||
4538 | *other_ino = di_key.objectid; | ||
4539 | } else { | ||
4540 | ret = -EAGAIN; | ||
4541 | } | ||
4532 | goto out; | 4542 | goto out; |
4533 | } else if (IS_ERR(di)) { | 4543 | } else if (IS_ERR(di)) { |
4534 | ret = PTR_ERR(di); | 4544 | ret = PTR_ERR(di); |
@@ -4722,16 +4732,71 @@ again: | |||
4722 | if ((min_key.type == BTRFS_INODE_REF_KEY || | 4732 | if ((min_key.type == BTRFS_INODE_REF_KEY || |
4723 | min_key.type == BTRFS_INODE_EXTREF_KEY) && | 4733 | min_key.type == BTRFS_INODE_EXTREF_KEY) && |
4724 | BTRFS_I(inode)->generation == trans->transid) { | 4734 | BTRFS_I(inode)->generation == trans->transid) { |
4735 | u64 other_ino = 0; | ||
4736 | |||
4725 | ret = btrfs_check_ref_name_override(path->nodes[0], | 4737 | ret = btrfs_check_ref_name_override(path->nodes[0], |
4726 | path->slots[0], | 4738 | path->slots[0], |
4727 | &min_key, inode); | 4739 | &min_key, inode, |
4740 | &other_ino); | ||
4728 | if (ret < 0) { | 4741 | if (ret < 0) { |
4729 | err = ret; | 4742 | err = ret; |
4730 | goto out_unlock; | 4743 | goto out_unlock; |
4731 | } else if (ret > 0) { | 4744 | } else if (ret > 0) { |
4732 | err = 1; | 4745 | struct btrfs_key inode_key; |
4733 | btrfs_set_log_full_commit(root->fs_info, trans); | 4746 | struct inode *other_inode; |
4734 | goto out_unlock; | 4747 | |
4748 | if (ins_nr > 0) { | ||
4749 | ins_nr++; | ||
4750 | } else { | ||
4751 | ins_nr = 1; | ||
4752 | ins_start_slot = path->slots[0]; | ||
4753 | } | ||
4754 | ret = copy_items(trans, inode, dst_path, path, | ||
4755 | &last_extent, ins_start_slot, | ||
4756 | ins_nr, inode_only, | ||
4757 | logged_isize); | ||
4758 | if (ret < 0) { | ||
4759 | err = ret; | ||
4760 | goto out_unlock; | ||
4761 | } | ||
4762 | ins_nr = 0; | ||
4763 | btrfs_release_path(path); | ||
4764 | inode_key.objectid = other_ino; | ||
4765 | inode_key.type = BTRFS_INODE_ITEM_KEY; | ||
4766 | inode_key.offset = 0; | ||
4767 | other_inode = btrfs_iget(root->fs_info->sb, | ||
4768 | &inode_key, root, | ||
4769 | NULL); | ||
4770 | /* | ||
4771 | * If the other inode that had a conflicting dir | ||
4772 | * entry was deleted in the current transaction, | ||
4773 | * we don't need to do more work nor fallback to | ||
4774 | * a transaction commit. | ||
4775 | */ | ||
4776 | if (IS_ERR(other_inode) && | ||
4777 | PTR_ERR(other_inode) == -ENOENT) { | ||
4778 | goto next_key; | ||
4779 | } else if (IS_ERR(other_inode)) { | ||
4780 | err = PTR_ERR(other_inode); | ||
4781 | goto out_unlock; | ||
4782 | } | ||
4783 | /* | ||
4784 | * We are safe logging the other inode without | ||
4785 | * acquiring its i_mutex as long as we log with | ||
4786 | * the LOG_INODE_EXISTS mode. We're safe against | ||
4787 | * concurrent renames of the other inode as well | ||
4788 | * because during a rename we pin the log and | ||
4789 | * update the log with the new name before we | ||
4790 | * unpin it. | ||
4791 | */ | ||
4792 | err = btrfs_log_inode(trans, root, other_inode, | ||
4793 | LOG_INODE_EXISTS, | ||
4794 | 0, LLONG_MAX, ctx); | ||
4795 | iput(other_inode); | ||
4796 | if (err) | ||
4797 | goto out_unlock; | ||
4798 | else | ||
4799 | goto next_key; | ||
4735 | } | 4800 | } |
4736 | } | 4801 | } |
4737 | 4802 | ||
@@ -4799,7 +4864,7 @@ next_slot: | |||
4799 | ins_nr = 0; | 4864 | ins_nr = 0; |
4800 | } | 4865 | } |
4801 | btrfs_release_path(path); | 4866 | btrfs_release_path(path); |
4802 | 4867 | next_key: | |
4803 | if (min_key.offset < (u64)-1) { | 4868 | if (min_key.offset < (u64)-1) { |
4804 | min_key.offset++; | 4869 | min_key.offset++; |
4805 | } else if (min_key.type < max_key.type) { | 4870 | } else if (min_key.type < max_key.type) { |
@@ -4993,8 +5058,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) | 5058 | if (!parent || d_really_is_negative(parent) || sb != parent->d_sb) |
4994 | break; | 5059 | break; |
4995 | 5060 | ||
4996 | if (IS_ROOT(parent)) | 5061 | if (IS_ROOT(parent)) { |
5062 | inode = d_inode(parent); | ||
5063 | if (btrfs_must_commit_transaction(trans, inode)) | ||
5064 | ret = 1; | ||
4997 | break; | 5065 | break; |
5066 | } | ||
4998 | 5067 | ||
4999 | parent = dget_parent(parent); | 5068 | parent = dget_parent(parent); |
5000 | dput(old_parent); | 5069 | dput(old_parent); |