aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/transaction.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-08-07 16:15:09 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-08-07 16:15:09 -0400
commit6702ed490ca0bb44e17131818a5a18b773957c5a (patch)
treef6bc4b77e58506a68f1ab539ca6c96854f39f92d /fs/btrfs/transaction.c
parent3c69faecb8d83cb2ef085a98b196a3fecea67725 (diff)
Btrfs: Add run time btree defrag, and an ioctl to force btree defrag
This adds two types of btree defrag, a run time form that tries to defrag recently allocated blocks in the btree when they are still in ram, and an ioctl that forces defrag of all btree blocks. File data blocks are not defragged yet, but this can make a huge difference in sequential btree reads. Signed-off-by: Chris Mason <chris.mason@oracle.com>
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 498626470a0..338a7199363 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: