aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/disk-io.c7
-rw-r--r--fs/btrfs/extent-tree.c1
-rw-r--r--fs/btrfs/file.c1
-rw-r--r--fs/btrfs/inode.c10
-rw-r--r--fs/btrfs/transaction.c59
-rw-r--r--fs/btrfs/transaction.h1
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 }
979out: 980out:
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);
2483out_unlock: 2483out_unlock:
2484 nr = trans->blocks_used; 2484 nr = trans->blocks_used;
2485 btrfs_end_transaction(trans, root); 2485 btrfs_end_transaction_throttle(trans, root);
2486fail: 2486fail:
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);
2539fail: 2539fail:
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
2610out_fail: 2610out_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
2614out_unlock: 2614out_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
3436out_fail: 3436out_fail:
3437 btrfs_end_transaction(trans, root); 3437 btrfs_end_transaction_throttle(trans, root);
3438out_unlock: 3438out_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
3549out_unlock: 3549out_unlock:
3550 nr = trans->blocks_used; 3550 nr = trans->blocks_used;
3551 btrfs_end_transaction(trans, root); 3551 btrfs_end_transaction_throttle(trans, root);
3552out_fail: 3552out_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
205void btrfs_throttle(struct btrfs_root *root)
206{
207 struct btrfs_fs_info *info = root->fs_info;
208
209harder:
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
205static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, 241static 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);
92int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, 92int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
93 struct btrfs_root *root); 93 struct btrfs_root *root);
94void btrfs_throttle(struct btrfs_root *root);
94#endif 95#endif