aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-07-29 16:15:18 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:05 -0400
commitab78c84de1ce4db1b2a2cef361625ad80abbab3f (patch)
treea9726645832b50da1da9a9690c4200c0f198ce7d /fs/btrfs
parent1a3f5d0400d786aec41ede15fec5710ad1a1d18b (diff)
Btrfs: Throttle operations if the reference cache gets too large
A large reference cache is directly related to a lot of work pending for the cleaner thread. This throttles back new operations based on the size of the reference cache so the cleaner thread will be able to keep up. Overall, this actually makes the FS faster because the cleaner thread will be more likely to find things in cache. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-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