aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/transaction.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r--fs/btrfs/transaction.c105
1 files changed, 87 insertions, 18 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 498626470a04..338a7199363b 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -29,6 +29,7 @@ extern struct kmem_cache *btrfs_transaction_cachep;
29static struct workqueue_struct *trans_wq; 29static struct workqueue_struct *trans_wq;
30 30
31#define BTRFS_ROOT_TRANS_TAG 0 31#define BTRFS_ROOT_TRANS_TAG 0
32#define BTRFS_ROOT_DEFRAG_TAG 1
32 33
33static void put_transaction(struct btrfs_transaction *transaction) 34static void put_transaction(struct btrfs_transaction *transaction)
34{ 35{
@@ -69,35 +70,41 @@ static int join_transaction(struct btrfs_root *root)
69 return 0; 70 return 0;
70} 71}
71 72
73static int record_root_in_trans(struct btrfs_root *root)
74{
75 u64 running_trans_id = root->fs_info->running_transaction->transid;
76 if (root->ref_cows && root->last_trans < running_trans_id) {
77 WARN_ON(root == root->fs_info->extent_root);
78 if (root->root_item.refs != 0) {
79 radix_tree_tag_set(&root->fs_info->fs_roots_radix,
80 (unsigned long)root->root_key.objectid,
81 BTRFS_ROOT_TRANS_TAG);
82 radix_tree_tag_set(&root->fs_info->fs_roots_radix,
83 (unsigned long)root->root_key.objectid,
84 BTRFS_ROOT_DEFRAG_TAG);
85 root->commit_root = root->node;
86 get_bh(root->node);
87 } else {
88 WARN_ON(1);
89 }
90 root->last_trans = running_trans_id;
91 }
92 return 0;
93}
94
72struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, 95struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
73 int num_blocks) 96 int num_blocks)
74{ 97{
75 struct btrfs_trans_handle *h = 98 struct btrfs_trans_handle *h =
76 kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); 99 kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
77 int ret; 100 int ret;
78 u64 running_trans_id;
79 101
80 mutex_lock(&root->fs_info->trans_mutex); 102 mutex_lock(&root->fs_info->trans_mutex);
81 ret = join_transaction(root); 103 ret = join_transaction(root);
82 BUG_ON(ret); 104 BUG_ON(ret);
83 running_trans_id = root->fs_info->running_transaction->transid;
84 105
85 if (root != root->fs_info->tree_root && root->last_trans < 106 record_root_in_trans(root);
86 running_trans_id) { 107 h->transid = root->fs_info->running_transaction->transid;
87 WARN_ON(root == root->fs_info->extent_root);
88 WARN_ON(root->ref_cows != 1);
89 if (root->root_item.refs != 0) {
90 radix_tree_tag_set(&root->fs_info->fs_roots_radix,
91 (unsigned long)root->root_key.objectid,
92 BTRFS_ROOT_TRANS_TAG);
93 root->commit_root = root->node;
94 get_bh(root->node);
95 } else {
96 WARN_ON(1);
97 }
98 }
99 root->last_trans = running_trans_id;
100 h->transid = running_trans_id;
101 h->transaction = root->fs_info->running_transaction; 108 h->transaction = root->fs_info->running_transaction;
102 h->blocks_reserved = num_blocks; 109 h->blocks_reserved = num_blocks;
103 h->blocks_used = 0; 110 h->blocks_used = 0;
@@ -155,6 +162,15 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
155 gang[i]); 162 gang[i]);
156 if (!page) 163 if (!page)
157 continue; 164 continue;
165 if (PageWriteback(page)) {
166 if (PageDirty(page))
167 wait_on_page_writeback(page);
168 else {
169 unlock_page(page);
170 page_cache_release(page);
171 continue;
172 }
173 }
158 err = write_one_page(page, 0); 174 err = write_one_page(page, 0);
159 if (err) 175 if (err)
160 werr = err; 176 werr = err;
@@ -299,6 +315,58 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans,
299 return err; 315 return err;
300} 316}
301 317
318int btrfs_defrag_dirty_roots(struct btrfs_fs_info *info)
319{
320 struct btrfs_root *gang[1];
321 struct btrfs_root *root;
322 struct btrfs_root *tree_root = info->tree_root;
323 struct btrfs_trans_handle *trans;
324 int i;
325 int ret;
326 int err = 0;
327 u64 last = 0;
328
329 trans = btrfs_start_transaction(tree_root, 1);
330 while(1) {
331 ret = radix_tree_gang_lookup_tag(&info->fs_roots_radix,
332 (void **)gang, last,
333 ARRAY_SIZE(gang),
334 BTRFS_ROOT_DEFRAG_TAG);
335 if (ret == 0)
336 break;
337 for (i = 0; i < ret; i++) {
338 root = gang[i];
339 last = root->root_key.objectid + 1;
340 radix_tree_tag_clear(&info->fs_roots_radix,
341 (unsigned long)root->root_key.objectid,
342 BTRFS_ROOT_DEFRAG_TAG);
343 if (root->defrag_running)
344 continue;
345
346 while (1) {
347 mutex_lock(&root->fs_info->trans_mutex);
348 record_root_in_trans(root);
349 mutex_unlock(&root->fs_info->trans_mutex);
350
351 root->defrag_running = 1;
352 err = btrfs_defrag_leaves(trans, root, 1);
353 btrfs_end_transaction(trans, tree_root);
354 mutex_unlock(&info->fs_mutex);
355
356 btrfs_btree_balance_dirty(root);
357
358 mutex_lock(&info->fs_mutex);
359 trans = btrfs_start_transaction(tree_root, 1);
360 if (err != -EAGAIN)
361 break;
362 }
363 root->defrag_running = 0;
364 }
365 }
366 btrfs_end_transaction(trans, tree_root);
367 return err;
368}
369
302static int drop_dirty_roots(struct btrfs_root *tree_root, 370static int drop_dirty_roots(struct btrfs_root *tree_root,
303 struct list_head *list) 371 struct list_head *list)
304{ 372{
@@ -475,6 +543,7 @@ void btrfs_transaction_cleaner(struct work_struct *work)
475 goto out; 543 goto out;
476 } 544 }
477 mutex_unlock(&root->fs_info->trans_mutex); 545 mutex_unlock(&root->fs_info->trans_mutex);
546 btrfs_defrag_dirty_roots(root->fs_info);
478 trans = btrfs_start_transaction(root, 1); 547 trans = btrfs_start_transaction(root, 1);
479 ret = btrfs_commit_transaction(trans, root); 548 ret = btrfs_commit_transaction(trans, root);
480out: 549out: