Btrfs: Add some simple throttling to wait for data=ordered and snapshot deletion

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index b55dba5..f0fb197 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -345,6 +345,7 @@
 	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 34cf1f1..e0940a3 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -631,6 +631,7 @@
 	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 @@
 	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 dae9fba..828f3a2 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -64,4 +64,5 @@
 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 0a5f4de..897242e 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -800,6 +800,7 @@
 		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 10cece1..2cb2dd3 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -610,6 +610,7 @@
 fail:
 	mutex_unlock(&root->fs_info->fs_mutex);
 	btrfs_btree_balance_dirty(root, nr);
+	btrfs_throttle(root);
 	return ret;
 }
 
@@ -644,6 +645,7 @@
 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 @@
 	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 @@
 	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 @@
 		iput(inode);
 	}
 	btrfs_btree_balance_dirty(root, nr);
+	btrfs_throttle(root);
 	return err;
 }
 
@@ -1633,6 +1638,7 @@
 		iput(inode);
 	}
 	btrfs_btree_balance_dirty(root, nr);
+	btrfs_throttle(root);
 	return err;
 }
 
@@ -1684,6 +1690,7 @@
 		iput(inode);
 	}
 	btrfs_btree_balance_dirty(root, nr);
+	btrfs_throttle(root);
 	return err;
 }
 
@@ -1752,6 +1759,7 @@
 	if (drop_on_err)
 		iput(inode);
 	btrfs_btree_balance_dirty(root, nr);
+	btrfs_throttle(root);
 	return err;
 }
 
@@ -2117,6 +2125,7 @@
 	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_commit:
 	mutex_unlock(&root->fs_info->fs_mutex);
 	btrfs_btree_balance_dirty(root, nr);
+	btrfs_throttle(root);
 	return ret;
 }
 
@@ -2287,6 +2297,7 @@
 fail_unlock:
 	mutex_unlock(&root->fs_info->fs_mutex);
 	btrfs_btree_balance_dirty(root, nr);
+	btrfs_throttle(root);
 	return ret;
 }
 
@@ -2827,6 +2838,7 @@
 		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 dc98653..614903f 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -424,6 +424,7 @@
 
 		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 @@
 			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 @@
 	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 @@
 		mutex_lock(&root->fs_info->fs_mutex);
 		mutex_lock(&root->fs_info->trans_mutex);
 	}
+	root->fs_info->throttles--;
 	return 0;
 }