diff options
Diffstat (limited to 'fs/btrfs')
| -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) { |
