Btrfs: smarter transaction writeback

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 8a2545f..f9b8864 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -45,6 +45,7 @@
 		cur_trans->use_count = 1;
 		cur_trans->commit_done = 0;
 		list_add_tail(&cur_trans->list, &root->fs_info->trans_list);
+		init_bit_radix(&cur_trans->dirty_pages);
 	}
 	cur_trans->num_writers++;
 	return 0;
@@ -106,8 +107,40 @@
 int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
 				     struct btrfs_root *root)
 {
-	filemap_write_and_wait(root->fs_info->btree_inode->i_mapping);
-	return 0;
+	unsigned long gang[16];
+	int ret;
+	int i;
+	int err;
+	int werr = 0;
+	struct page *page;
+	struct radix_tree_root *dirty_pages;
+	struct inode *btree_inode = root->fs_info->btree_inode;
+
+	if (!trans || !trans->transaction) {
+		return filemap_write_and_wait(btree_inode->i_mapping);
+	}
+	dirty_pages = &trans->transaction->dirty_pages;
+	while(1) {
+		ret = find_first_radix_bit(dirty_pages, gang, ARRAY_SIZE(gang));
+		if (!ret)
+			break;
+		for (i = 0; i < ret; i++) {
+			/* FIXME EIO */
+			clear_radix_bit(dirty_pages, gang[i]);
+			page = find_lock_page(btree_inode->i_mapping,
+					      gang[i]);
+			if (!page)
+				continue;
+			err = write_one_page(page, 0);
+			if (err)
+				werr = err;
+			page_cache_release(page);
+		}
+	}
+	err = filemap_fdatawait(btree_inode->i_mapping);
+	if (err)
+		werr = err;
+	return werr;
 }
 
 int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,