2 * Copyright (C) 2007 Oracle. All rights reserved.
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.
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.
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.
19 #include <linux/sched.h>
22 #include "print-tree.h"
23 #include "transaction.h"
25 static void reada_defrag(struct btrfs_root
*root
,
26 struct extent_buffer
*node
)
35 blocksize
= btrfs_level_size(root
, btrfs_header_level(node
) - 1);
36 nritems
= btrfs_header_nritems(node
);
37 for (i
= 0; i
< nritems
; i
++) {
38 bytenr
= btrfs_node_blockptr(node
, i
);
39 gen
= btrfs_node_ptr_generation(node
, i
);
40 ret
= readahead_tree_block(root
, bytenr
, blocksize
, gen
);
46 static int defrag_walk_down(struct btrfs_trans_handle
*trans
,
47 struct btrfs_root
*root
,
48 struct btrfs_path
*path
, int *level
,
49 int cache_only
, u64
*last_ret
)
51 struct extent_buffer
*next
;
52 struct extent_buffer
*cur
;
59 WARN_ON(*level
>= BTRFS_MAX_LEVEL
);
61 if (root
->fs_info
->extent_root
== root
)
64 if (*level
== 1 && cache_only
&& path
->nodes
[1] &&
65 !btrfs_buffer_defrag(path
->nodes
[1])) {
70 WARN_ON(*level
>= BTRFS_MAX_LEVEL
);
71 cur
= path
->nodes
[*level
];
73 if (!cache_only
&& *level
> 1 && path
->slots
[*level
] == 0)
74 reada_defrag(root
, cur
);
76 if (btrfs_header_level(cur
) != *level
)
79 if (path
->slots
[*level
] >=
80 btrfs_header_nritems(cur
))
84 WARN_ON(btrfs_header_generation(path
->nodes
[*level
]) !=
86 ret
= btrfs_realloc_node(trans
, root
,
90 &root
->defrag_progress
);
92 btrfs_extent_post_op(trans
, root
);
96 bytenr
= btrfs_node_blockptr(cur
, path
->slots
[*level
]);
97 ptr_gen
= btrfs_node_ptr_generation(cur
, path
->slots
[*level
]);
100 next
= btrfs_find_tree_block(root
, bytenr
,
101 btrfs_level_size(root
, *level
- 1));
102 if (!next
|| !btrfs_buffer_uptodate(next
, ptr_gen
) ||
103 !btrfs_buffer_defrag(next
)) {
104 free_extent_buffer(next
);
105 path
->slots
[*level
]++;
109 next
= read_tree_block(root
, bytenr
,
110 btrfs_level_size(root
, *level
- 1),
113 ret
= btrfs_cow_block(trans
, root
, next
, path
->nodes
[*level
],
114 path
->slots
[*level
], &next
);
117 btrfs_extent_post_op(trans
, root
);
119 WARN_ON(*level
<= 0);
120 if (path
->nodes
[*level
-1])
121 free_extent_buffer(path
->nodes
[*level
-1]);
122 path
->nodes
[*level
-1] = next
;
123 *level
= btrfs_header_level(next
);
124 path
->slots
[*level
] = 0;
127 WARN_ON(*level
>= BTRFS_MAX_LEVEL
);
129 btrfs_clear_buffer_defrag(path
->nodes
[*level
]);
131 free_extent_buffer(path
->nodes
[*level
]);
132 path
->nodes
[*level
] = NULL
;
134 WARN_ON(ret
&& ret
!= -EAGAIN
);
138 static int defrag_walk_up(struct btrfs_trans_handle
*trans
,
139 struct btrfs_root
*root
,
140 struct btrfs_path
*path
, int *level
,
145 struct extent_buffer
*node
;
147 for(i
= *level
; i
< BTRFS_MAX_LEVEL
- 1 && path
->nodes
[i
]; i
++) {
148 slot
= path
->slots
[i
];
149 if (slot
< btrfs_header_nritems(path
->nodes
[i
]) - 1) {
152 node
= path
->nodes
[i
];
154 btrfs_node_key_to_cpu(node
, &root
->defrag_progress
,
156 root
->defrag_level
= i
;
159 btrfs_clear_buffer_defrag(path
->nodes
[*level
]);
160 free_extent_buffer(path
->nodes
[*level
]);
161 path
->nodes
[*level
] = NULL
;
168 int btrfs_defrag_leaves(struct btrfs_trans_handle
*trans
,
169 struct btrfs_root
*root
, int cache_only
)
171 struct btrfs_path
*path
= NULL
;
172 struct extent_buffer
*tmp
;
181 if (root
->fs_info
->extent_root
== root
)
184 if (root
->ref_cows
== 0 && !is_extent
)
187 if (btrfs_test_opt(root
, SSD
))
190 path
= btrfs_alloc_path();
194 level
= btrfs_header_level(root
->node
);
200 if (root
->defrag_progress
.objectid
== 0) {
201 extent_buffer_get(root
->node
);
202 ret
= btrfs_cow_block(trans
, root
, root
->node
, NULL
, 0, &tmp
);
204 path
->nodes
[level
] = root
->node
;
205 path
->slots
[level
] = 0;
207 btrfs_extent_post_op(trans
, root
);
209 level
= root
->defrag_level
;
210 path
->lowest_level
= level
;
211 wret
= btrfs_search_slot(trans
, root
, &root
->defrag_progress
,
215 btrfs_extent_post_op(trans
, root
);
222 while(level
> 0 && !path
->nodes
[level
])
225 if (!path
->nodes
[level
]) {
232 wret
= defrag_walk_down(trans
, root
, path
, &level
, cache_only
,
239 wret
= defrag_walk_up(trans
, root
, path
, &level
, cache_only
);
248 for (i
= 0; i
<= orig_level
; i
++) {
249 if (path
->nodes
[i
]) {
250 free_extent_buffer(path
->nodes
[i
]);
251 path
->nodes
[i
] = NULL
;
256 btrfs_free_path(path
);
257 if (ret
!= -EAGAIN
) {
258 memset(&root
->defrag_progress
, 0,
259 sizeof(root
->defrag_progress
));
This page took 0.039621 seconds and 6 git commands to generate.