diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/delayed-inode.c | 22 | ||||
-rw-r--r-- | fs/btrfs/delayed-inode.h | 2 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 97 |
3 files changed, 83 insertions, 38 deletions
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 2399f4086915..21d91a8073ee 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c | |||
@@ -1113,8 +1113,8 @@ static int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, | |||
1113 | * Returns < 0 on error and returns with an aborted transaction with any | 1113 | * Returns < 0 on error and returns with an aborted transaction with any |
1114 | * outstanding delayed items cleaned up. | 1114 | * outstanding delayed items cleaned up. |
1115 | */ | 1115 | */ |
1116 | int btrfs_run_delayed_items(struct btrfs_trans_handle *trans, | 1116 | static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans, |
1117 | struct btrfs_root *root) | 1117 | struct btrfs_root *root, int nr) |
1118 | { | 1118 | { |
1119 | struct btrfs_root *curr_root = root; | 1119 | struct btrfs_root *curr_root = root; |
1120 | struct btrfs_delayed_root *delayed_root; | 1120 | struct btrfs_delayed_root *delayed_root; |
@@ -1122,6 +1122,7 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans, | |||
1122 | struct btrfs_path *path; | 1122 | struct btrfs_path *path; |
1123 | struct btrfs_block_rsv *block_rsv; | 1123 | struct btrfs_block_rsv *block_rsv; |
1124 | int ret = 0; | 1124 | int ret = 0; |
1125 | bool count = (nr > 0); | ||
1125 | 1126 | ||
1126 | if (trans->aborted) | 1127 | if (trans->aborted) |
1127 | return -EIO; | 1128 | return -EIO; |
@@ -1137,7 +1138,7 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans, | |||
1137 | delayed_root = btrfs_get_delayed_root(root); | 1138 | delayed_root = btrfs_get_delayed_root(root); |
1138 | 1139 | ||
1139 | curr_node = btrfs_first_delayed_node(delayed_root); | 1140 | curr_node = btrfs_first_delayed_node(delayed_root); |
1140 | while (curr_node) { | 1141 | while (curr_node && (!count || (count && nr--))) { |
1141 | curr_root = curr_node->root; | 1142 | curr_root = curr_node->root; |
1142 | ret = btrfs_insert_delayed_items(trans, path, curr_root, | 1143 | ret = btrfs_insert_delayed_items(trans, path, curr_root, |
1143 | curr_node); | 1144 | curr_node); |
@@ -1149,6 +1150,7 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans, | |||
1149 | path, curr_node); | 1150 | path, curr_node); |
1150 | if (ret) { | 1151 | if (ret) { |
1151 | btrfs_release_delayed_node(curr_node); | 1152 | btrfs_release_delayed_node(curr_node); |
1153 | curr_node = NULL; | ||
1152 | btrfs_abort_transaction(trans, root, ret); | 1154 | btrfs_abort_transaction(trans, root, ret); |
1153 | break; | 1155 | break; |
1154 | } | 1156 | } |
@@ -1158,12 +1160,26 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans, | |||
1158 | btrfs_release_delayed_node(prev_node); | 1160 | btrfs_release_delayed_node(prev_node); |
1159 | } | 1161 | } |
1160 | 1162 | ||
1163 | if (curr_node) | ||
1164 | btrfs_release_delayed_node(curr_node); | ||
1161 | btrfs_free_path(path); | 1165 | btrfs_free_path(path); |
1162 | trans->block_rsv = block_rsv; | 1166 | trans->block_rsv = block_rsv; |
1163 | 1167 | ||
1164 | return ret; | 1168 | return ret; |
1165 | } | 1169 | } |
1166 | 1170 | ||
1171 | int btrfs_run_delayed_items(struct btrfs_trans_handle *trans, | ||
1172 | struct btrfs_root *root) | ||
1173 | { | ||
1174 | return __btrfs_run_delayed_items(trans, root, -1); | ||
1175 | } | ||
1176 | |||
1177 | int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans, | ||
1178 | struct btrfs_root *root, int nr) | ||
1179 | { | ||
1180 | return __btrfs_run_delayed_items(trans, root, nr); | ||
1181 | } | ||
1182 | |||
1167 | static int __btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, | 1183 | static int __btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, |
1168 | struct btrfs_delayed_node *node) | 1184 | struct btrfs_delayed_node *node) |
1169 | { | 1185 | { |
diff --git a/fs/btrfs/delayed-inode.h b/fs/btrfs/delayed-inode.h index f5aa4023d3e1..4f808e1baeed 100644 --- a/fs/btrfs/delayed-inode.h +++ b/fs/btrfs/delayed-inode.h | |||
@@ -107,6 +107,8 @@ int btrfs_inode_delayed_dir_index_count(struct inode *inode); | |||
107 | 107 | ||
108 | int btrfs_run_delayed_items(struct btrfs_trans_handle *trans, | 108 | int btrfs_run_delayed_items(struct btrfs_trans_handle *trans, |
109 | struct btrfs_root *root); | 109 | struct btrfs_root *root); |
110 | int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans, | ||
111 | struct btrfs_root *root, int nr); | ||
110 | 112 | ||
111 | void btrfs_balance_delayed_items(struct btrfs_root *root); | 113 | void btrfs_balance_delayed_items(struct btrfs_root *root); |
112 | 114 | ||
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 6e1d36702ff7..3cde907a25a5 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -3728,6 +3728,60 @@ commit: | |||
3728 | return btrfs_commit_transaction(trans, root); | 3728 | return btrfs_commit_transaction(trans, root); |
3729 | } | 3729 | } |
3730 | 3730 | ||
3731 | enum flush_state { | ||
3732 | FLUSH_DELALLOC = 1, | ||
3733 | FLUSH_DELALLOC_WAIT = 2, | ||
3734 | FLUSH_DELAYED_ITEMS_NR = 3, | ||
3735 | FLUSH_DELAYED_ITEMS = 4, | ||
3736 | COMMIT_TRANS = 5, | ||
3737 | }; | ||
3738 | |||
3739 | static int flush_space(struct btrfs_root *root, | ||
3740 | struct btrfs_space_info *space_info, u64 num_bytes, | ||
3741 | u64 orig_bytes, int state) | ||
3742 | { | ||
3743 | struct btrfs_trans_handle *trans; | ||
3744 | int nr; | ||
3745 | int ret; | ||
3746 | |||
3747 | switch (state) { | ||
3748 | case FLUSH_DELALLOC: | ||
3749 | case FLUSH_DELALLOC_WAIT: | ||
3750 | ret = shrink_delalloc(root, num_bytes, | ||
3751 | state == FLUSH_DELALLOC_WAIT); | ||
3752 | if (ret > 0) | ||
3753 | ret = 0; | ||
3754 | break; | ||
3755 | case FLUSH_DELAYED_ITEMS_NR: | ||
3756 | case FLUSH_DELAYED_ITEMS: | ||
3757 | if (state == FLUSH_DELAYED_ITEMS_NR) { | ||
3758 | u64 bytes = btrfs_calc_trans_metadata_size(root, 1); | ||
3759 | |||
3760 | nr = (int)div64_u64(num_bytes, bytes); | ||
3761 | if (!nr) | ||
3762 | nr = 1; | ||
3763 | nr *= 2; | ||
3764 | } else { | ||
3765 | nr = -1; | ||
3766 | } | ||
3767 | trans = btrfs_join_transaction(root); | ||
3768 | if (IS_ERR(trans)) { | ||
3769 | ret = PTR_ERR(trans); | ||
3770 | break; | ||
3771 | } | ||
3772 | ret = btrfs_run_delayed_items_nr(trans, root, nr); | ||
3773 | btrfs_end_transaction(trans, root); | ||
3774 | break; | ||
3775 | case COMMIT_TRANS: | ||
3776 | ret = may_commit_transaction(root, space_info, orig_bytes, 0); | ||
3777 | break; | ||
3778 | default: | ||
3779 | ret = -ENOSPC; | ||
3780 | break; | ||
3781 | } | ||
3782 | |||
3783 | return ret; | ||
3784 | } | ||
3731 | /** | 3785 | /** |
3732 | * reserve_metadata_bytes - try to reserve bytes from the block_rsv's space | 3786 | * reserve_metadata_bytes - try to reserve bytes from the block_rsv's space |
3733 | * @root - the root we're allocating for | 3787 | * @root - the root we're allocating for |
@@ -3749,11 +3803,10 @@ static int reserve_metadata_bytes(struct btrfs_root *root, | |||
3749 | struct btrfs_space_info *space_info = block_rsv->space_info; | 3803 | struct btrfs_space_info *space_info = block_rsv->space_info; |
3750 | u64 used; | 3804 | u64 used; |
3751 | u64 num_bytes = orig_bytes; | 3805 | u64 num_bytes = orig_bytes; |
3752 | int retries = 0; | 3806 | int flush_state = FLUSH_DELALLOC; |
3753 | int ret = 0; | 3807 | int ret = 0; |
3754 | bool committed = false; | ||
3755 | bool flushing = false; | 3808 | bool flushing = false; |
3756 | bool wait_ordered = false; | 3809 | bool committed = false; |
3757 | 3810 | ||
3758 | again: | 3811 | again: |
3759 | ret = 0; | 3812 | ret = 0; |
@@ -3812,9 +3865,8 @@ again: | |||
3812 | * amount plus the amount of bytes that we need for this | 3865 | * amount plus the amount of bytes that we need for this |
3813 | * reservation. | 3866 | * reservation. |
3814 | */ | 3867 | */ |
3815 | wait_ordered = true; | ||
3816 | num_bytes = used - space_info->total_bytes + | 3868 | num_bytes = used - space_info->total_bytes + |
3817 | (orig_bytes * (retries + 1)); | 3869 | (orig_bytes * 2); |
3818 | } | 3870 | } |
3819 | 3871 | ||
3820 | if (ret) { | 3872 | if (ret) { |
@@ -3867,8 +3919,6 @@ again: | |||
3867 | trace_btrfs_space_reservation(root->fs_info, | 3919 | trace_btrfs_space_reservation(root->fs_info, |
3868 | "space_info", space_info->flags, orig_bytes, 1); | 3920 | "space_info", space_info->flags, orig_bytes, 1); |
3869 | ret = 0; | 3921 | ret = 0; |
3870 | } else { | ||
3871 | wait_ordered = true; | ||
3872 | } | 3922 | } |
3873 | } | 3923 | } |
3874 | 3924 | ||
@@ -3887,36 +3937,13 @@ again: | |||
3887 | if (!ret || !flush) | 3937 | if (!ret || !flush) |
3888 | goto out; | 3938 | goto out; |
3889 | 3939 | ||
3890 | /* | 3940 | ret = flush_space(root, space_info, num_bytes, orig_bytes, |
3891 | * We do synchronous shrinking since we don't actually unreserve | 3941 | flush_state); |
3892 | * metadata until after the IO is completed. | 3942 | flush_state++; |
3893 | */ | 3943 | if (!ret) |
3894 | ret = shrink_delalloc(root, num_bytes, wait_ordered); | ||
3895 | if (ret < 0) | ||
3896 | goto out; | ||
3897 | |||
3898 | ret = 0; | ||
3899 | |||
3900 | /* | ||
3901 | * So if we were overcommitted it's possible that somebody else flushed | ||
3902 | * out enough space and we simply didn't have enough space to reclaim, | ||
3903 | * so go back around and try again. | ||
3904 | */ | ||
3905 | if (retries < 2) { | ||
3906 | wait_ordered = true; | ||
3907 | retries++; | ||
3908 | goto again; | 3944 | goto again; |
3909 | } | 3945 | else if (flush_state <= COMMIT_TRANS) |
3910 | |||
3911 | ret = -ENOSPC; | ||
3912 | if (committed) | ||
3913 | goto out; | ||
3914 | |||
3915 | ret = may_commit_transaction(root, space_info, orig_bytes, 0); | ||
3916 | if (!ret) { | ||
3917 | committed = true; | ||
3918 | goto again; | 3946 | goto again; |
3919 | } | ||
3920 | 3947 | ||
3921 | out: | 3948 | out: |
3922 | if (flushing) { | 3949 | if (flushing) { |