diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/relocation.c | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 16e0c6fbdbed..0f001c14eaf4 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
@@ -2240,13 +2240,28 @@ again: | |||
2240 | } | 2240 | } |
2241 | 2241 | ||
2242 | static noinline_for_stack | 2242 | static noinline_for_stack |
2243 | void free_reloc_roots(struct list_head *list) | ||
2244 | { | ||
2245 | struct btrfs_root *reloc_root; | ||
2246 | |||
2247 | while (!list_empty(list)) { | ||
2248 | reloc_root = list_entry(list->next, struct btrfs_root, | ||
2249 | root_list); | ||
2250 | __update_reloc_root(reloc_root, 1); | ||
2251 | free_extent_buffer(reloc_root->node); | ||
2252 | free_extent_buffer(reloc_root->commit_root); | ||
2253 | kfree(reloc_root); | ||
2254 | } | ||
2255 | } | ||
2256 | |||
2257 | static noinline_for_stack | ||
2243 | int merge_reloc_roots(struct reloc_control *rc) | 2258 | int merge_reloc_roots(struct reloc_control *rc) |
2244 | { | 2259 | { |
2245 | struct btrfs_root *root; | 2260 | struct btrfs_root *root; |
2246 | struct btrfs_root *reloc_root; | 2261 | struct btrfs_root *reloc_root; |
2247 | LIST_HEAD(reloc_roots); | 2262 | LIST_HEAD(reloc_roots); |
2248 | int found = 0; | 2263 | int found = 0; |
2249 | int ret; | 2264 | int ret = 0; |
2250 | again: | 2265 | again: |
2251 | root = rc->extent_root; | 2266 | root = rc->extent_root; |
2252 | 2267 | ||
@@ -2272,20 +2287,33 @@ again: | |||
2272 | BUG_ON(root->reloc_root != reloc_root); | 2287 | BUG_ON(root->reloc_root != reloc_root); |
2273 | 2288 | ||
2274 | ret = merge_reloc_root(rc, root); | 2289 | ret = merge_reloc_root(rc, root); |
2275 | BUG_ON(ret); | 2290 | if (ret) |
2291 | goto out; | ||
2276 | } else { | 2292 | } else { |
2277 | list_del_init(&reloc_root->root_list); | 2293 | list_del_init(&reloc_root->root_list); |
2278 | } | 2294 | } |
2279 | ret = btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0, 1); | 2295 | ret = btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0, 1); |
2280 | BUG_ON(ret < 0); | 2296 | if (ret < 0) { |
2297 | if (list_empty(&reloc_root->root_list)) | ||
2298 | list_add_tail(&reloc_root->root_list, | ||
2299 | &reloc_roots); | ||
2300 | goto out; | ||
2301 | } | ||
2281 | } | 2302 | } |
2282 | 2303 | ||
2283 | if (found) { | 2304 | if (found) { |
2284 | found = 0; | 2305 | found = 0; |
2285 | goto again; | 2306 | goto again; |
2286 | } | 2307 | } |
2308 | out: | ||
2309 | if (ret) { | ||
2310 | btrfs_std_error(root->fs_info, ret); | ||
2311 | if (!list_empty(&reloc_roots)) | ||
2312 | free_reloc_roots(&reloc_roots); | ||
2313 | } | ||
2314 | |||
2287 | BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root)); | 2315 | BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root)); |
2288 | return 0; | 2316 | return ret; |
2289 | } | 2317 | } |
2290 | 2318 | ||
2291 | static void free_block_list(struct rb_root *blocks) | 2319 | static void free_block_list(struct rb_root *blocks) |
@@ -4266,14 +4294,9 @@ int btrfs_recover_relocation(struct btrfs_root *root) | |||
4266 | out_free: | 4294 | out_free: |
4267 | kfree(rc); | 4295 | kfree(rc); |
4268 | out: | 4296 | out: |
4269 | while (!list_empty(&reloc_roots)) { | 4297 | if (!list_empty(&reloc_roots)) |
4270 | reloc_root = list_entry(reloc_roots.next, | 4298 | free_reloc_roots(&reloc_roots); |
4271 | struct btrfs_root, root_list); | 4299 | |
4272 | list_del(&reloc_root->root_list); | ||
4273 | free_extent_buffer(reloc_root->node); | ||
4274 | free_extent_buffer(reloc_root->commit_root); | ||
4275 | kfree(reloc_root); | ||
4276 | } | ||
4277 | btrfs_free_path(path); | 4300 | btrfs_free_path(path); |
4278 | 4301 | ||
4279 | if (err == 0) { | 4302 | if (err == 0) { |