Btrfs: Add per-root block accounting and sysfs entries

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 18abea8..2b15daa 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -236,6 +236,7 @@
 struct dirty_root {
 	struct list_head list;
 	struct btrfs_root *root;
+	struct btrfs_root *latest_root;
 };
 
 int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list)
@@ -278,6 +279,15 @@
 					btrfs_root_blocknr(&root->root_item));
 				brelse(root->commit_root);
 				root->commit_root = NULL;
+
+				/* make sure to update the root on disk
+				 * so we get any updates to the block used
+				 * counts
+				 */
+				err = btrfs_update_root(trans,
+						root->fs_info->tree_root,
+						&root->root_key,
+						&root->root_item);
 				continue;
 			}
 			dirty = kmalloc(sizeof(*dirty), GFP_NOFS);
@@ -291,6 +301,7 @@
 
 			memcpy(dirty->root, root, sizeof(*root));
 			dirty->root->node = root->commit_root;
+			dirty->latest_root = root;
 			root->commit_root = NULL;
 
 			root->root_key.offset = root->fs_info->generation;
@@ -384,20 +395,29 @@
 {
 	struct dirty_root *dirty;
 	struct btrfs_trans_handle *trans;
+	u64 num_blocks;
+	u64 blocks_used;
 	int ret = 0;
 	int err;
 
 	while(!list_empty(list)) {
+		struct btrfs_root *root;
+
 		mutex_lock(&tree_root->fs_info->fs_mutex);
 		dirty = list_entry(list->next, struct dirty_root, list);
 		list_del_init(&dirty->list);
 
+		num_blocks = btrfs_root_blocks_used(&dirty->root->root_item);
+		root = dirty->latest_root;
+
 		while(1) {
 			trans = btrfs_start_transaction(tree_root, 1);
+
 			ret = btrfs_drop_snapshot(trans, dirty->root);
 			if (ret != -EAGAIN) {
 				break;
 			}
+
 			err = btrfs_update_root(trans,
 					tree_root,
 					&dirty->root->root_key,
@@ -414,9 +434,19 @@
 			mutex_lock(&tree_root->fs_info->fs_mutex);
 		}
 		BUG_ON(ret);
+
+		num_blocks -= btrfs_root_blocks_used(&dirty->root->root_item);
+		blocks_used = btrfs_root_blocks_used(&root->root_item);
+		if (num_blocks) {
+			record_root_in_trans(root);
+			btrfs_set_root_blocks_used(&root->root_item,
+						   blocks_used - num_blocks);
+		}
 		ret = btrfs_del_root(trans, tree_root, &dirty->root->root_key);
-		if (ret)
+		if (ret) {
+			BUG();
 			break;
+		}
 		ret = btrfs_end_transaction(trans, tree_root);
 		BUG_ON(ret);
 
@@ -534,10 +564,12 @@
 	wake_up(&cur_trans->commit_wait);
 	put_transaction(cur_trans);
 	put_transaction(cur_trans);
+
 	if (root->fs_info->closing)
 		list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots);
 	else
 		list_splice_init(&dirty_fs_roots, &root->fs_info->dead_roots);
+
 	mutex_unlock(&root->fs_info->trans_mutex);
 	kmem_cache_free(btrfs_trans_handle_cachep, trans);