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
)
33 nritems
= btrfs_header_nritems(node
);
34 for (i
= 0; i
< nritems
; i
++) {
35 blocknr
= btrfs_node_blockptr(node
, i
);
36 ret
= readahead_tree_block(root
, blocknr
);
42 static int defrag_walk_down(struct btrfs_trans_handle
*trans
,
43 struct btrfs_root
*root
,
44 struct btrfs_path
*path
, int *level
,
45 int cache_only
, u64
*last_ret
)
47 struct extent_buffer
*next
;
48 struct extent_buffer
*cur
;
54 WARN_ON(*level
>= BTRFS_MAX_LEVEL
);
56 if (root
->fs_info
->extent_root
== root
)
61 WARN_ON(*level
>= BTRFS_MAX_LEVEL
);
62 cur
= path
->nodes
[*level
];
64 if (!cache_only
&& *level
> 1 && path
->slots
[*level
] == 0)
65 reada_defrag(root
, cur
);
67 if (btrfs_header_level(cur
) != *level
)
70 if (path
->slots
[*level
] >=
71 btrfs_header_nritems(cur
))
75 ret
= btrfs_realloc_node(trans
, root
,
77 cache_only
, last_ret
);
79 btrfs_extent_post_op(trans
, root
);
83 blocknr
= btrfs_node_blockptr(cur
, path
->slots
[*level
]);
86 next
= btrfs_find_tree_block(root
, blocknr
);
87 /* FIXME, test for defrag */
88 if (!next
|| !btrfs_buffer_uptodate(next
)) {
89 free_extent_buffer(next
);
90 path
->slots
[*level
]++;
94 next
= read_tree_block(root
, blocknr
);
96 ret
= btrfs_cow_block(trans
, root
, next
, path
->nodes
[*level
],
97 path
->slots
[*level
], &next
);
99 ret
= btrfs_realloc_node(trans
, root
, next
, cache_only
,
104 btrfs_extent_post_op(trans
, root
);
106 WARN_ON(*level
<= 0);
107 if (path
->nodes
[*level
-1])
108 free_extent_buffer(path
->nodes
[*level
-1]);
109 path
->nodes
[*level
-1] = next
;
110 *level
= btrfs_header_level(next
);
111 path
->slots
[*level
] = 0;
114 WARN_ON(*level
>= BTRFS_MAX_LEVEL
);
116 clear_buffer_defrag(path
->nodes
[*level
]);
117 clear_buffer_defrag_done(path
->nodes
[*level
]);
119 free_extent_buffer(path
->nodes
[*level
]);
120 path
->nodes
[*level
] = NULL
;
126 static int defrag_walk_up(struct btrfs_trans_handle
*trans
,
127 struct btrfs_root
*root
,
128 struct btrfs_path
*path
, int *level
,
133 struct extent_buffer
*node
;
135 for(i
= *level
; i
< BTRFS_MAX_LEVEL
- 1 && path
->nodes
[i
]; i
++) {
136 slot
= path
->slots
[i
];
137 if (slot
< btrfs_header_nritems(path
->nodes
[i
]) - 1) {
140 node
= path
->nodes
[i
];
142 btrfs_node_key_to_cpu(node
, &root
->defrag_progress
,
144 root
->defrag_level
= i
;
148 clear_buffer_defrag(path->nodes[*level]);
149 clear_buffer_defrag_done(path->nodes[*level]);
151 free_extent_buffer(path
->nodes
[*level
]);
152 path
->nodes
[*level
] = NULL
;
159 int btrfs_defrag_leaves(struct btrfs_trans_handle
*trans
,
160 struct btrfs_root
*root
, int cache_only
)
162 struct btrfs_path
*path
= NULL
;
163 struct extent_buffer
*tmp
;
172 if (root
->fs_info
->extent_root
== root
)
175 if (root
->ref_cows
== 0 && !is_extent
)
178 path
= btrfs_alloc_path();
182 level
= btrfs_header_level(root
->node
);
187 if (root
->defrag_progress
.objectid
== 0) {
188 extent_buffer_get(root
->node
);
189 ret
= btrfs_cow_block(trans
, root
, root
->node
, NULL
, 0, &tmp
);
191 ret
= btrfs_realloc_node(trans
, root
, root
->node
, cache_only
,
194 path
->nodes
[level
] = root
->node
;
195 path
->slots
[level
] = 0;
197 btrfs_extent_post_op(trans
, root
);
199 level
= root
->defrag_level
;
200 path
->lowest_level
= level
;
201 wret
= btrfs_search_slot(trans
, root
, &root
->defrag_progress
,
205 btrfs_extent_post_op(trans
, root
);
212 while(level
> 0 && !path
->nodes
[level
])
215 if (!path
->nodes
[level
]) {
222 wret
= defrag_walk_down(trans
, root
, path
, &level
, cache_only
,
229 wret
= defrag_walk_up(trans
, root
, path
, &level
, cache_only
);
237 for (i
= 0; i
<= orig_level
; i
++) {
238 if (path
->nodes
[i
]) {
239 free_extent_buffer(path
->nodes
[i
]);
245 btrfs_free_path(path
);
246 if (ret
!= -EAGAIN
) {
247 memset(&root
->defrag_progress
, 0,
248 sizeof(root
->defrag_progress
));
This page took 0.045167 seconds and 5 git commands to generate.