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
)
34 blocksize
= btrfs_level_size(root
, btrfs_header_level(node
) - 1);
35 nritems
= btrfs_header_nritems(node
);
36 for (i
= 0; i
< nritems
; i
++) {
37 bytenr
= btrfs_node_blockptr(node
, i
);
38 ret
= readahead_tree_block(root
, bytenr
, blocksize
);
44 static int defrag_walk_down(struct btrfs_trans_handle
*trans
,
45 struct btrfs_root
*root
,
46 struct btrfs_path
*path
, int *level
,
47 int cache_only
, u64
*last_ret
)
49 struct extent_buffer
*next
;
50 struct extent_buffer
*cur
;
56 WARN_ON(*level
>= BTRFS_MAX_LEVEL
);
58 if (root
->fs_info
->extent_root
== root
)
63 WARN_ON(*level
>= BTRFS_MAX_LEVEL
);
64 cur
= path
->nodes
[*level
];
66 if (!cache_only
&& *level
> 1 && path
->slots
[*level
] == 0)
67 reada_defrag(root
, cur
);
69 if (btrfs_header_level(cur
) != *level
)
72 if (path
->slots
[*level
] >=
73 btrfs_header_nritems(cur
))
77 ret
= btrfs_realloc_node(trans
, root
,
81 &root
->defrag_progress
);
83 btrfs_extent_post_op(trans
, root
);
87 bytenr
= btrfs_node_blockptr(cur
, path
->slots
[*level
]);
90 next
= btrfs_find_tree_block(root
, bytenr
,
91 btrfs_level_size(root
, *level
- 1));
92 if (!next
|| !btrfs_buffer_uptodate(next
) ||
93 !btrfs_buffer_defrag(next
)) {
94 free_extent_buffer(next
);
95 path
->slots
[*level
]++;
99 next
= read_tree_block(root
, bytenr
,
100 btrfs_level_size(root
, *level
- 1));
102 ret
= btrfs_cow_block(trans
, root
, next
, path
->nodes
[*level
],
103 path
->slots
[*level
], &next
);
106 btrfs_extent_post_op(trans
, root
);
108 WARN_ON(*level
<= 0);
109 if (path
->nodes
[*level
-1])
110 free_extent_buffer(path
->nodes
[*level
-1]);
111 path
->nodes
[*level
-1] = next
;
112 *level
= btrfs_header_level(next
);
113 path
->slots
[*level
] = 0;
116 WARN_ON(*level
>= BTRFS_MAX_LEVEL
);
118 btrfs_clear_buffer_defrag(path
->nodes
[*level
]);
120 free_extent_buffer(path
->nodes
[*level
]);
121 path
->nodes
[*level
] = NULL
;
123 WARN_ON(ret
&& ret
!= -EAGAIN
);
127 static int defrag_walk_up(struct btrfs_trans_handle
*trans
,
128 struct btrfs_root
*root
,
129 struct btrfs_path
*path
, int *level
,
134 struct extent_buffer
*node
;
136 for(i
= *level
; i
< BTRFS_MAX_LEVEL
- 1 && path
->nodes
[i
]; i
++) {
137 slot
= path
->slots
[i
];
138 if (slot
< btrfs_header_nritems(path
->nodes
[i
]) - 1) {
141 node
= path
->nodes
[i
];
143 btrfs_node_key_to_cpu(node
, &root
->defrag_progress
,
145 root
->defrag_level
= i
;
148 btrfs_clear_buffer_defrag(path
->nodes
[*level
]);
149 free_extent_buffer(path
->nodes
[*level
]);
150 path
->nodes
[*level
] = NULL
;
157 int btrfs_defrag_leaves(struct btrfs_trans_handle
*trans
,
158 struct btrfs_root
*root
, int cache_only
)
160 struct btrfs_path
*path
= NULL
;
161 struct extent_buffer
*tmp
;
170 if (root
->fs_info
->extent_root
== root
)
173 if (root
->ref_cows
== 0 && !is_extent
)
176 path
= btrfs_alloc_path();
180 level
= btrfs_header_level(root
->node
);
186 if (root
->defrag_progress
.objectid
== 0) {
187 extent_buffer_get(root
->node
);
188 ret
= btrfs_cow_block(trans
, root
, root
->node
, NULL
, 0, &tmp
);
190 path
->nodes
[level
] = root
->node
;
191 path
->slots
[level
] = 0;
193 btrfs_extent_post_op(trans
, root
);
195 level
= root
->defrag_level
;
196 path
->lowest_level
= level
;
197 wret
= btrfs_search_slot(trans
, root
, &root
->defrag_progress
,
201 btrfs_extent_post_op(trans
, root
);
208 while(level
> 0 && !path
->nodes
[level
])
211 if (!path
->nodes
[level
]) {
218 wret
= defrag_walk_down(trans
, root
, path
, &level
, cache_only
,
225 wret
= defrag_walk_up(trans
, root
, path
, &level
, cache_only
);
233 for (i
= 0; i
<= orig_level
; i
++) {
234 if (path
->nodes
[i
]) {
235 free_extent_buffer(path
->nodes
[i
]);
236 path
->nodes
[i
] = NULL
;
241 btrfs_free_path(path
);
242 if (ret
!= -EAGAIN
) {
243 memset(&root
->defrag_progress
, 0,
244 sizeof(root
->defrag_progress
));
This page took 0.046288 seconds and 5 git commands to generate.