Line data Source code
1 : /*
2 : * Copyright (C) 2007 Oracle. All rights reserved.
3 : *
4 : * This program is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU General Public
6 : * License v2 as published by the Free Software Foundation.
7 : *
8 : * This program is distributed in the hope that it will be useful,
9 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 : * General Public License for more details.
12 : *
13 : * You should have received a copy of the GNU General Public
14 : * License along with this program; if not, write to the
15 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 : * Boston, MA 021110-1307, USA.
17 : */
18 :
19 : #include <linux/sched.h>
20 : #include "ctree.h"
21 : #include "disk-io.h"
22 : #include "print-tree.h"
23 : #include "transaction.h"
24 : #include "locking.h"
25 :
26 : /*
27 : * Defrag all the leaves in a given btree.
28 : * Read all the leaves and try to get key order to
29 : * better reflect disk order
30 : */
31 :
32 4 : int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
33 : struct btrfs_root *root)
34 : {
35 : struct btrfs_path *path = NULL;
36 : struct btrfs_key key;
37 : int ret = 0;
38 : int wret;
39 : int level;
40 : int next_key_ret = 0;
41 4 : u64 last_ret = 0;
42 : u64 min_trans = 0;
43 :
44 4 : if (root->fs_info->extent_root == root) {
45 : /*
46 : * there's recursion here right now in the tree locking,
47 : * we can't defrag the extent root without deadlock
48 : */
49 : goto out;
50 : }
51 :
52 2 : if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))
53 : goto out;
54 :
55 2 : if (btrfs_test_opt(root, SSD))
56 : goto out;
57 :
58 2 : path = btrfs_alloc_path();
59 2 : if (!path)
60 : return -ENOMEM;
61 :
62 2 : level = btrfs_header_level(root->node);
63 :
64 2 : if (level == 0)
65 : goto out;
66 :
67 0 : if (root->defrag_progress.objectid == 0) {
68 0 : struct extent_buffer *root_node;
69 : u32 nritems;
70 :
71 0 : root_node = btrfs_lock_root_node(root);
72 : btrfs_set_lock_blocking(root_node);
73 : nritems = btrfs_header_nritems(root_node);
74 0 : root->defrag_max.objectid = 0;
75 : /* from above we know this is not a leaf */
76 0 : btrfs_node_key_to_cpu(root_node, &root->defrag_max,
77 0 : nritems - 1);
78 0 : btrfs_tree_unlock(root_node);
79 0 : free_extent_buffer(root_node);
80 0 : memset(&key, 0, sizeof(key));
81 : } else {
82 0 : memcpy(&key, &root->defrag_progress, sizeof(key));
83 : }
84 :
85 0 : path->keep_locks = 1;
86 :
87 0 : ret = btrfs_search_forward(root, &key, path, min_trans);
88 0 : if (ret < 0)
89 : goto out;
90 0 : if (ret > 0) {
91 : ret = 0;
92 : goto out;
93 : }
94 0 : btrfs_release_path(path);
95 0 : wret = btrfs_search_slot(trans, root, &key, path, 0, 1);
96 :
97 0 : if (wret < 0) {
98 : ret = wret;
99 : goto out;
100 : }
101 0 : if (!path->nodes[1]) {
102 : ret = 0;
103 : goto out;
104 : }
105 0 : path->slots[1] = btrfs_header_nritems(path->nodes[1]);
106 0 : next_key_ret = btrfs_find_next_key(root, path, &key, 1,
107 : min_trans);
108 0 : ret = btrfs_realloc_node(trans, root,
109 : path->nodes[1], 0,
110 : &last_ret,
111 : &root->defrag_progress);
112 0 : if (ret) {
113 0 : WARN_ON(ret == -EAGAIN);
114 : goto out;
115 : }
116 0 : if (next_key_ret == 0) {
117 0 : memcpy(&root->defrag_progress, &key, sizeof(key));
118 : ret = -EAGAIN;
119 : }
120 : out:
121 4 : if (path)
122 2 : btrfs_free_path(path);
123 4 : if (ret == -EAGAIN) {
124 0 : if (root->defrag_max.objectid > root->defrag_progress.objectid)
125 : goto done;
126 0 : if (root->defrag_max.type > root->defrag_progress.type)
127 : goto done;
128 0 : if (root->defrag_max.offset > root->defrag_progress.offset)
129 : goto done;
130 : ret = 0;
131 : }
132 : done:
133 4 : if (ret != -EAGAIN) {
134 4 : memset(&root->defrag_progress, 0,
135 : sizeof(root->defrag_progress));
136 4 : root->defrag_trans_start = trans->transid;
137 : }
138 4 : return ret;
139 : }
|