diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/extent-tree.c | 71 |
1 files changed, 42 insertions, 29 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 7527523c2d2d..376656f65b33 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -1323,8 +1323,25 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, | |||
1323 | int btrfs_extent_post_op(struct btrfs_trans_handle *trans, | 1323 | int btrfs_extent_post_op(struct btrfs_trans_handle *trans, |
1324 | struct btrfs_root *root) | 1324 | struct btrfs_root *root) |
1325 | { | 1325 | { |
1326 | finish_current_insert(trans, root->fs_info->extent_root, 1); | 1326 | u64 start; |
1327 | del_pending_extents(trans, root->fs_info->extent_root, 1); | 1327 | u64 end; |
1328 | int ret; | ||
1329 | |||
1330 | while(1) { | ||
1331 | finish_current_insert(trans, root->fs_info->extent_root, 1); | ||
1332 | del_pending_extents(trans, root->fs_info->extent_root, 1); | ||
1333 | |||
1334 | /* is there more work to do? */ | ||
1335 | ret = find_first_extent_bit(&root->fs_info->pending_del, | ||
1336 | 0, &start, &end, EXTENT_WRITEBACK); | ||
1337 | if (!ret) | ||
1338 | continue; | ||
1339 | ret = find_first_extent_bit(&root->fs_info->extent_ins, | ||
1340 | 0, &start, &end, EXTENT_WRITEBACK); | ||
1341 | if (!ret) | ||
1342 | continue; | ||
1343 | break; | ||
1344 | } | ||
1328 | return 0; | 1345 | return 0; |
1329 | } | 1346 | } |
1330 | 1347 | ||
@@ -2211,13 +2228,12 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, | |||
2211 | u64 end; | 2228 | u64 end; |
2212 | u64 priv; | 2229 | u64 priv; |
2213 | u64 search = 0; | 2230 | u64 search = 0; |
2214 | u64 skipped = 0; | ||
2215 | struct btrfs_fs_info *info = extent_root->fs_info; | 2231 | struct btrfs_fs_info *info = extent_root->fs_info; |
2216 | struct btrfs_path *path; | 2232 | struct btrfs_path *path; |
2217 | struct pending_extent_op *extent_op, *tmp; | 2233 | struct pending_extent_op *extent_op, *tmp; |
2218 | struct list_head insert_list, update_list; | 2234 | struct list_head insert_list, update_list; |
2219 | int ret; | 2235 | int ret; |
2220 | int num_inserts = 0, max_inserts; | 2236 | int num_inserts = 0, max_inserts, restart = 0; |
2221 | 2237 | ||
2222 | path = btrfs_alloc_path(); | 2238 | path = btrfs_alloc_path(); |
2223 | INIT_LIST_HEAD(&insert_list); | 2239 | INIT_LIST_HEAD(&insert_list); |
@@ -2233,19 +2249,19 @@ again: | |||
2233 | ret = find_first_extent_bit(&info->extent_ins, search, &start, | 2249 | ret = find_first_extent_bit(&info->extent_ins, search, &start, |
2234 | &end, EXTENT_WRITEBACK); | 2250 | &end, EXTENT_WRITEBACK); |
2235 | if (ret) { | 2251 | if (ret) { |
2236 | if (skipped && all && !num_inserts && | 2252 | if (restart && !num_inserts && |
2237 | list_empty(&update_list)) { | 2253 | list_empty(&update_list)) { |
2238 | skipped = 0; | 2254 | restart = 0; |
2239 | search = 0; | 2255 | search = 0; |
2240 | continue; | 2256 | continue; |
2241 | } | 2257 | } |
2242 | mutex_unlock(&info->extent_ins_mutex); | ||
2243 | break; | 2258 | break; |
2244 | } | 2259 | } |
2245 | 2260 | ||
2246 | ret = try_lock_extent(&info->extent_ins, start, end, GFP_NOFS); | 2261 | ret = try_lock_extent(&info->extent_ins, start, end, GFP_NOFS); |
2247 | if (!ret) { | 2262 | if (!ret) { |
2248 | skipped = 1; | 2263 | if (all) |
2264 | restart = 1; | ||
2249 | search = end + 1; | 2265 | search = end + 1; |
2250 | if (need_resched()) { | 2266 | if (need_resched()) { |
2251 | mutex_unlock(&info->extent_ins_mutex); | 2267 | mutex_unlock(&info->extent_ins_mutex); |
@@ -2264,7 +2280,7 @@ again: | |||
2264 | list_add_tail(&extent_op->list, &insert_list); | 2280 | list_add_tail(&extent_op->list, &insert_list); |
2265 | search = end + 1; | 2281 | search = end + 1; |
2266 | if (num_inserts == max_inserts) { | 2282 | if (num_inserts == max_inserts) { |
2267 | mutex_unlock(&info->extent_ins_mutex); | 2283 | restart = 1; |
2268 | break; | 2284 | break; |
2269 | } | 2285 | } |
2270 | } else if (extent_op->type == PENDING_BACKREF_UPDATE) { | 2286 | } else if (extent_op->type == PENDING_BACKREF_UPDATE) { |
@@ -2280,7 +2296,6 @@ again: | |||
2280 | * somebody marked this thing for deletion then just unlock it and be | 2296 | * somebody marked this thing for deletion then just unlock it and be |
2281 | * done, the free_extents will handle it | 2297 | * done, the free_extents will handle it |
2282 | */ | 2298 | */ |
2283 | mutex_lock(&info->extent_ins_mutex); | ||
2284 | list_for_each_entry_safe(extent_op, tmp, &update_list, list) { | 2299 | list_for_each_entry_safe(extent_op, tmp, &update_list, list) { |
2285 | clear_extent_bits(&info->extent_ins, extent_op->bytenr, | 2300 | clear_extent_bits(&info->extent_ins, extent_op->bytenr, |
2286 | extent_op->bytenr + extent_op->num_bytes - 1, | 2301 | extent_op->bytenr + extent_op->num_bytes - 1, |
@@ -2302,6 +2317,10 @@ again: | |||
2302 | if (!list_empty(&update_list)) { | 2317 | if (!list_empty(&update_list)) { |
2303 | ret = update_backrefs(trans, extent_root, path, &update_list); | 2318 | ret = update_backrefs(trans, extent_root, path, &update_list); |
2304 | BUG_ON(ret); | 2319 | BUG_ON(ret); |
2320 | |||
2321 | /* we may have COW'ed new blocks, so lets start over */ | ||
2322 | if (all) | ||
2323 | restart = 1; | ||
2305 | } | 2324 | } |
2306 | 2325 | ||
2307 | /* | 2326 | /* |
@@ -2309,9 +2328,9 @@ again: | |||
2309 | * need to make sure everything is cleaned then reset everything and | 2328 | * need to make sure everything is cleaned then reset everything and |
2310 | * go back to the beginning | 2329 | * go back to the beginning |
2311 | */ | 2330 | */ |
2312 | if (!num_inserts && all && skipped) { | 2331 | if (!num_inserts && restart) { |
2313 | search = 0; | 2332 | search = 0; |
2314 | skipped = 0; | 2333 | restart = 0; |
2315 | INIT_LIST_HEAD(&update_list); | 2334 | INIT_LIST_HEAD(&update_list); |
2316 | INIT_LIST_HEAD(&insert_list); | 2335 | INIT_LIST_HEAD(&insert_list); |
2317 | goto again; | 2336 | goto again; |
@@ -2368,27 +2387,19 @@ again: | |||
2368 | BUG_ON(ret); | 2387 | BUG_ON(ret); |
2369 | 2388 | ||
2370 | /* | 2389 | /* |
2371 | * if we broke out of the loop in order to insert stuff because we hit | 2390 | * if restart is set for whatever reason we need to go back and start |
2372 | * the maximum number of inserts at a time we can handle, then loop | 2391 | * searching through the pending list again. |
2373 | * back and pick up where we left off | 2392 | * |
2393 | * We just inserted some extents, which could have resulted in new | ||
2394 | * blocks being allocated, which would result in new blocks needing | ||
2395 | * updates, so if all is set we _must_ restart to get the updated | ||
2396 | * blocks. | ||
2374 | */ | 2397 | */ |
2375 | if (num_inserts == max_inserts) { | 2398 | if (restart || all) { |
2376 | INIT_LIST_HEAD(&insert_list); | ||
2377 | INIT_LIST_HEAD(&update_list); | ||
2378 | num_inserts = 0; | ||
2379 | goto again; | ||
2380 | } | ||
2381 | |||
2382 | /* | ||
2383 | * again, if we need to make absolutely sure there are no more pending | ||
2384 | * extent operations left and we know that we skipped some, go back to | ||
2385 | * the beginning and do it all again | ||
2386 | */ | ||
2387 | if (all && skipped) { | ||
2388 | INIT_LIST_HEAD(&insert_list); | 2399 | INIT_LIST_HEAD(&insert_list); |
2389 | INIT_LIST_HEAD(&update_list); | 2400 | INIT_LIST_HEAD(&update_list); |
2390 | search = 0; | 2401 | search = 0; |
2391 | skipped = 0; | 2402 | restart = 0; |
2392 | num_inserts = 0; | 2403 | num_inserts = 0; |
2393 | goto again; | 2404 | goto again; |
2394 | } | 2405 | } |
@@ -2709,6 +2720,8 @@ again: | |||
2709 | goto again; | 2720 | goto again; |
2710 | } | 2721 | } |
2711 | 2722 | ||
2723 | if (!err) | ||
2724 | finish_current_insert(trans, extent_root, 0); | ||
2712 | return err; | 2725 | return err; |
2713 | } | 2726 | } |
2714 | 2727 | ||