diff options
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 7 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 1 | ||||
-rw-r--r-- | fs/btrfs/file.c | 1 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 10 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 59 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 1 |
7 files changed, 58 insertions, 22 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 4eca0aa1ce74..5517dfc6f71c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -580,6 +580,7 @@ struct btrfs_fs_info { | |||
580 | int do_barriers; | 580 | int do_barriers; |
581 | int closing; | 581 | int closing; |
582 | atomic_t throttles; | 582 | atomic_t throttles; |
583 | atomic_t throttle_gen; | ||
583 | 584 | ||
584 | u64 total_pinned; | 585 | u64 total_pinned; |
585 | struct list_head dirty_cowonly_roots; | 586 | struct list_head dirty_cowonly_roots; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index eccdf13a95ac..27ffa9b7ddc8 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -1171,8 +1171,10 @@ static int transaction_kthread(void *arg) | |||
1171 | vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE); | 1171 | vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE); |
1172 | mutex_lock(&root->fs_info->transaction_kthread_mutex); | 1172 | mutex_lock(&root->fs_info->transaction_kthread_mutex); |
1173 | 1173 | ||
1174 | printk("btrfs: total reference cache size %Lu\n", | 1174 | if (root->fs_info->total_ref_cache_size > 20 * 1024 * 1024) { |
1175 | root->fs_info->total_ref_cache_size); | 1175 | printk("btrfs: total reference cache size %Lu\n", |
1176 | root->fs_info->total_ref_cache_size); | ||
1177 | } | ||
1176 | 1178 | ||
1177 | mutex_lock(&root->fs_info->trans_mutex); | 1179 | mutex_lock(&root->fs_info->trans_mutex); |
1178 | cur = root->fs_info->running_transaction; | 1180 | cur = root->fs_info->running_transaction; |
@@ -1256,6 +1258,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1256 | btrfs_mapping_init(&fs_info->mapping_tree); | 1258 | btrfs_mapping_init(&fs_info->mapping_tree); |
1257 | atomic_set(&fs_info->nr_async_submits, 0); | 1259 | atomic_set(&fs_info->nr_async_submits, 0); |
1258 | atomic_set(&fs_info->throttles, 0); | 1260 | atomic_set(&fs_info->throttles, 0); |
1261 | atomic_set(&fs_info->throttle_gen, 0); | ||
1259 | fs_info->sb = sb; | 1262 | fs_info->sb = sb; |
1260 | fs_info->max_extent = (u64)-1; | 1263 | fs_info->max_extent = (u64)-1; |
1261 | fs_info->max_inline = 8192 * 1024; | 1264 | fs_info->max_inline = 8192 * 1024; |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0e294cfaa60c..6290cf41d647 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -2650,6 +2650,7 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
2650 | } | 2650 | } |
2651 | } | 2651 | } |
2652 | while(1) { | 2652 | while(1) { |
2653 | atomic_inc(&root->fs_info->throttle_gen); | ||
2653 | wret = walk_down_tree(trans, root, path, &level); | 2654 | wret = walk_down_tree(trans, root, path, &level); |
2654 | if (wret > 0) | 2655 | if (wret > 0) |
2655 | break; | 2656 | break; |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 3efec25e34b0..ded5281f8463 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -974,6 +974,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
974 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, num_pages); | 974 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, num_pages); |
975 | if (num_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1) | 975 | if (num_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1) |
976 | btrfs_btree_balance_dirty(root, 1); | 976 | btrfs_btree_balance_dirty(root, 1); |
977 | btrfs_throttle(root); | ||
977 | cond_resched(); | 978 | cond_resched(); |
978 | } | 979 | } |
979 | out: | 980 | out: |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 4f977ea5497e..7c87f863d6f7 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -2482,7 +2482,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, | |||
2482 | btrfs_update_inode_block_group(trans, dir); | 2482 | btrfs_update_inode_block_group(trans, dir); |
2483 | out_unlock: | 2483 | out_unlock: |
2484 | nr = trans->blocks_used; | 2484 | nr = trans->blocks_used; |
2485 | btrfs_end_transaction(trans, root); | 2485 | btrfs_end_transaction_throttle(trans, root); |
2486 | fail: | 2486 | fail: |
2487 | if (drop_inode) { | 2487 | if (drop_inode) { |
2488 | inode_dec_link_count(inode); | 2488 | inode_dec_link_count(inode); |
@@ -2535,7 +2535,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, | |||
2535 | drop_inode = 1; | 2535 | drop_inode = 1; |
2536 | 2536 | ||
2537 | nr = trans->blocks_used; | 2537 | nr = trans->blocks_used; |
2538 | btrfs_end_transaction(trans, root); | 2538 | btrfs_end_transaction_throttle(trans, root); |
2539 | fail: | 2539 | fail: |
2540 | if (drop_inode) { | 2540 | if (drop_inode) { |
2541 | inode_dec_link_count(inode); | 2541 | inode_dec_link_count(inode); |
@@ -2609,7 +2609,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
2609 | 2609 | ||
2610 | out_fail: | 2610 | out_fail: |
2611 | nr = trans->blocks_used; | 2611 | nr = trans->blocks_used; |
2612 | btrfs_end_transaction(trans, root); | 2612 | btrfs_end_transaction_throttle(trans, root); |
2613 | 2613 | ||
2614 | out_unlock: | 2614 | out_unlock: |
2615 | if (drop_on_err) | 2615 | if (drop_on_err) |
@@ -3434,7 +3434,7 @@ static int btrfs_rename(struct inode * old_dir, struct dentry *old_dentry, | |||
3434 | goto out_fail; | 3434 | goto out_fail; |
3435 | 3435 | ||
3436 | out_fail: | 3436 | out_fail: |
3437 | btrfs_end_transaction(trans, root); | 3437 | btrfs_end_transaction_throttle(trans, root); |
3438 | out_unlock: | 3438 | out_unlock: |
3439 | return ret; | 3439 | return ret; |
3440 | } | 3440 | } |
@@ -3548,7 +3548,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, | |||
3548 | 3548 | ||
3549 | out_unlock: | 3549 | out_unlock: |
3550 | nr = trans->blocks_used; | 3550 | nr = trans->blocks_used; |
3551 | btrfs_end_transaction(trans, root); | 3551 | btrfs_end_transaction_throttle(trans, root); |
3552 | out_fail: | 3552 | out_fail: |
3553 | if (drop_inode) { | 3553 | if (drop_inode) { |
3554 | inode_dec_link_count(inode); | 3554 | inode_dec_link_count(inode); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index fcef3cae0c92..b8be6703189a 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -202,35 +202,64 @@ static noinline int wait_for_commit(struct btrfs_root *root, | |||
202 | return 0; | 202 | return 0; |
203 | } | 203 | } |
204 | 204 | ||
205 | void btrfs_throttle(struct btrfs_root *root) | ||
206 | { | ||
207 | struct btrfs_fs_info *info = root->fs_info; | ||
208 | |||
209 | harder: | ||
210 | if (atomic_read(&info->throttles)) { | ||
211 | DEFINE_WAIT(wait); | ||
212 | int thr; | ||
213 | int harder_count = 0; | ||
214 | thr = atomic_read(&info->throttle_gen); | ||
215 | |||
216 | do { | ||
217 | prepare_to_wait(&info->transaction_throttle, | ||
218 | &wait, TASK_UNINTERRUPTIBLE); | ||
219 | if (!atomic_read(&info->throttles)) { | ||
220 | finish_wait(&info->transaction_throttle, &wait); | ||
221 | break; | ||
222 | } | ||
223 | schedule(); | ||
224 | finish_wait(&info->transaction_throttle, &wait); | ||
225 | } while (thr == atomic_read(&info->throttle_gen)); | ||
226 | |||
227 | if (harder_count < 5 && | ||
228 | info->total_ref_cache_size > 5 * 1024 * 1024) { | ||
229 | harder_count++; | ||
230 | goto harder; | ||
231 | } | ||
232 | |||
233 | if (harder_count < 10 && | ||
234 | info->total_ref_cache_size > 10 * 1024 * 1024) { | ||
235 | harder_count++; | ||
236 | goto harder; | ||
237 | } | ||
238 | } | ||
239 | } | ||
240 | |||
205 | static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | 241 | static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, |
206 | struct btrfs_root *root, int throttle) | 242 | struct btrfs_root *root, int throttle) |
207 | { | 243 | { |
208 | struct btrfs_transaction *cur_trans; | 244 | struct btrfs_transaction *cur_trans; |
245 | struct btrfs_fs_info *info = root->fs_info; | ||
209 | 246 | ||
210 | mutex_lock(&root->fs_info->trans_mutex); | 247 | mutex_lock(&info->trans_mutex); |
211 | cur_trans = root->fs_info->running_transaction; | 248 | cur_trans = info->running_transaction; |
212 | WARN_ON(cur_trans != trans->transaction); | 249 | WARN_ON(cur_trans != trans->transaction); |
213 | WARN_ON(cur_trans->num_writers < 1); | 250 | WARN_ON(cur_trans->num_writers < 1); |
214 | cur_trans->num_writers--; | 251 | cur_trans->num_writers--; |
215 | 252 | ||
216 | if (waitqueue_active(&cur_trans->writer_wait)) | 253 | if (waitqueue_active(&cur_trans->writer_wait)) |
217 | wake_up(&cur_trans->writer_wait); | 254 | wake_up(&cur_trans->writer_wait); |
218 | |||
219 | if (throttle && atomic_read(&root->fs_info->throttles)) { | ||
220 | DEFINE_WAIT(wait); | ||
221 | mutex_unlock(&root->fs_info->trans_mutex); | ||
222 | prepare_to_wait(&root->fs_info->transaction_throttle, &wait, | ||
223 | TASK_UNINTERRUPTIBLE); | ||
224 | if (atomic_read(&root->fs_info->throttles)) | ||
225 | schedule(); | ||
226 | finish_wait(&root->fs_info->transaction_throttle, &wait); | ||
227 | mutex_lock(&root->fs_info->trans_mutex); | ||
228 | } | ||
229 | |||
230 | put_transaction(cur_trans); | 255 | put_transaction(cur_trans); |
231 | mutex_unlock(&root->fs_info->trans_mutex); | 256 | mutex_unlock(&info->trans_mutex); |
232 | memset(trans, 0, sizeof(*trans)); | 257 | memset(trans, 0, sizeof(*trans)); |
233 | kmem_cache_free(btrfs_trans_handle_cachep, trans); | 258 | kmem_cache_free(btrfs_trans_handle_cachep, trans); |
259 | |||
260 | if (throttle) | ||
261 | btrfs_throttle(root); | ||
262 | |||
234 | return 0; | 263 | return 0; |
235 | } | 264 | } |
236 | 265 | ||
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 11fbdeceb26c..df2ca2aad1c0 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -91,4 +91,5 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
91 | struct btrfs_root *root); | 91 | struct btrfs_root *root); |
92 | int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, | 92 | int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, |
93 | struct btrfs_root *root); | 93 | struct btrfs_root *root); |
94 | void btrfs_throttle(struct btrfs_root *root); | ||
94 | #endif | 95 | #endif |