diff options
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 7 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 1 | ||||
-rw-r--r-- | fs/btrfs/file.c | 1 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 12 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 4 |
6 files changed, 26 insertions, 0 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index b55dba58dfa..f0fb1978553 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -345,6 +345,7 @@ struct btrfs_fs_info { struct completion kobj_unregister; int do_barriers; int closing; + unsigned long throttles; u64 total_pinned; spinlock_t delalloc_lock; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 34cf1f1f47b..e0940a39ff0 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -631,6 +631,7 @@ struct btrfs_root *open_ctree(struct super_block *sb) fs_info->tree_root = tree_root; fs_info->extent_root = extent_root; fs_info->sb = sb; + fs_info->throttles = 0; fs_info->mount_opt = 0; fs_info->max_extent = (u64)-1; fs_info->delalloc_bytes = 0; @@ -889,6 +890,12 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf) set_extent_buffer_dirty(&BTRFS_I(btree_inode)->extent_tree, buf); } +void btrfs_throttle(struct btrfs_root *root) +{ + if (root->fs_info->throttles) + congestion_wait(WRITE, HZ/10); +} + void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr) { balance_dirty_pages_ratelimited_nr( diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index dae9fba8efc..828f3a2081b 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h @@ -64,4 +64,5 @@ int btrfs_clear_buffer_defrag_done(struct extent_buffer *buf); int btrfs_read_buffer(struct extent_buffer *buf); u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len); void btrfs_csum_final(u32 crc, char *result); +void btrfs_throttle(struct btrfs_root *root); #endif diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 0a5f4defe59..897242e87fa 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -800,6 +800,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, balance_dirty_pages_ratelimited_nr(inode->i_mapping, num_pages); if (num_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1) btrfs_btree_balance_dirty(root, 1); + btrfs_throttle(root); cond_resched(); } out: diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 10cece11dbd..2cb2dd32407 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -610,6 +610,7 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) fail: mutex_unlock(&root->fs_info->fs_mutex); btrfs_btree_balance_dirty(root, nr); + btrfs_throttle(root); return ret; } @@ -644,6 +645,7 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) fail: mutex_unlock(&root->fs_info->fs_mutex); btrfs_btree_balance_dirty(root, nr); + btrfs_throttle(root); if (ret && !err) err = ret; @@ -1010,6 +1012,7 @@ void btrfs_delete_inode(struct inode *inode) btrfs_end_transaction(trans, root); mutex_unlock(&root->fs_info->fs_mutex); btrfs_btree_balance_dirty(root, nr); + btrfs_throttle(root); return; no_delete_lock: @@ -1017,6 +1020,7 @@ no_delete_lock: btrfs_end_transaction(trans, root); mutex_unlock(&root->fs_info->fs_mutex); btrfs_btree_balance_dirty(root, nr); + btrfs_throttle(root); no_delete: clear_inode(inode); } @@ -1574,6 +1578,7 @@ fail: iput(inode); } btrfs_btree_balance_dirty(root, nr); + btrfs_throttle(root); return err; } @@ -1633,6 +1638,7 @@ fail: iput(inode); } btrfs_btree_balance_dirty(root, nr); + btrfs_throttle(root); return err; } @@ -1684,6 +1690,7 @@ fail: iput(inode); } btrfs_btree_balance_dirty(root, nr); + btrfs_throttle(root); return err; } @@ -1752,6 +1759,7 @@ out_unlock: if (drop_on_err) iput(inode); btrfs_btree_balance_dirty(root, nr); + btrfs_throttle(root); return err; } @@ -2117,6 +2125,7 @@ static void btrfs_truncate(struct inode *inode) BUG_ON(ret); mutex_unlock(&root->fs_info->fs_mutex); btrfs_btree_balance_dirty(root, nr); + btrfs_throttle(root); } static int noinline create_subvol(struct btrfs_root *root, char *name, @@ -2245,6 +2254,7 @@ fail: fail_commit: mutex_unlock(&root->fs_info->fs_mutex); btrfs_btree_balance_dirty(root, nr); + btrfs_throttle(root); return ret; } @@ -2287,6 +2297,7 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) fail_unlock: mutex_unlock(&root->fs_info->fs_mutex); btrfs_btree_balance_dirty(root, nr); + btrfs_throttle(root); return ret; } @@ -2827,6 +2838,7 @@ out_fail: iput(inode); } btrfs_btree_balance_dirty(root, nr); + btrfs_throttle(root); return err; } diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index dc9865323e3..614903f5c88 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -424,6 +424,7 @@ static int drop_dirty_roots(struct btrfs_root *tree_root, num_bytes = btrfs_root_used(&dirty->root->root_item); root = dirty->latest_root; + root->fs_info->throttles++; while(1) { trans = btrfs_start_transaction(tree_root, 1); @@ -447,6 +448,7 @@ static int drop_dirty_roots(struct btrfs_root *tree_root, mutex_lock(&tree_root->fs_info->fs_mutex); } BUG_ON(ret); + root->fs_info->throttles--; num_bytes -= btrfs_root_used(&dirty->root->root_item); bytes_used = btrfs_root_used(&root->root_item); @@ -484,6 +486,7 @@ int btrfs_write_ordered_inodes(struct btrfs_trans_handle *trans, u64 objectid = 0; int ret; + root->fs_info->throttles++; while(1) { ret = btrfs_find_first_ordered_inode( &cur_trans->ordered_inode_tree, @@ -523,6 +526,7 @@ int btrfs_write_ordered_inodes(struct btrfs_trans_handle *trans, mutex_lock(&root->fs_info->fs_mutex); mutex_lock(&root->fs_info->trans_mutex); } + root->fs_info->throttles--; return 0; } |