Branch data 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 : 0 : 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 : 0 : u64 last_ret = 0;
42 : : u64 min_trans = 0;
43 : :
44 [ # # ]: 0 : 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 [ # # ]: 0 : if (root->ref_cows == 0)
53 : : goto out;
54 : :
55 [ # # ]: 0 : if (btrfs_test_opt(root, SSD))
56 : : goto out;
57 : :
58 : 0 : path = btrfs_alloc_path();
59 [ # # ]: 0 : if (!path)
60 : : return -ENOMEM;
61 : :
62 : 0 : level = btrfs_header_level(root->node);
63 : :
64 [ # # ]: 0 : 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 [ # # ]: 0 : if (path)
122 : 0 : btrfs_free_path(path);
123 [ # # ]: 0 : 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 [ # # ]: 0 : if (ret != -EAGAIN) {
134 : 0 : memset(&root->defrag_progress, 0,
135 : : sizeof(root->defrag_progress));
136 : 0 : root->defrag_trans_start = trans->transid;
137 : : }
138 : 0 : return ret;
139 : : }
|