diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 219 |
1 files changed, 200 insertions, 19 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 9027bb1e7466..ef96381569a4 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -278,8 +278,7 @@ static int process_one_buffer(struct btrfs_root *log, | |||
278 | struct walk_control *wc, u64 gen) | 278 | struct walk_control *wc, u64 gen) |
279 | { | 279 | { |
280 | if (wc->pin) | 280 | if (wc->pin) |
281 | btrfs_pin_extent_for_log_replay(wc->trans, | 281 | btrfs_pin_extent_for_log_replay(log->fs_info->extent_root, |
282 | log->fs_info->extent_root, | ||
283 | eb->start, eb->len); | 282 | eb->start, eb->len); |
284 | 283 | ||
285 | if (btrfs_buffer_uptodate(eb, gen, 0)) { | 284 | if (btrfs_buffer_uptodate(eb, gen, 0)) { |
@@ -318,6 +317,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, | |||
318 | unsigned long src_ptr; | 317 | unsigned long src_ptr; |
319 | unsigned long dst_ptr; | 318 | unsigned long dst_ptr; |
320 | int overwrite_root = 0; | 319 | int overwrite_root = 0; |
320 | bool inode_item = key->type == BTRFS_INODE_ITEM_KEY; | ||
321 | 321 | ||
322 | if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) | 322 | if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) |
323 | overwrite_root = 1; | 323 | overwrite_root = 1; |
@@ -327,6 +327,9 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, | |||
327 | 327 | ||
328 | /* look for the key in the destination tree */ | 328 | /* look for the key in the destination tree */ |
329 | ret = btrfs_search_slot(NULL, root, key, path, 0, 0); | 329 | ret = btrfs_search_slot(NULL, root, key, path, 0, 0); |
330 | if (ret < 0) | ||
331 | return ret; | ||
332 | |||
330 | if (ret == 0) { | 333 | if (ret == 0) { |
331 | char *src_copy; | 334 | char *src_copy; |
332 | char *dst_copy; | 335 | char *dst_copy; |
@@ -368,6 +371,30 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, | |||
368 | return 0; | 371 | return 0; |
369 | } | 372 | } |
370 | 373 | ||
374 | /* | ||
375 | * We need to load the old nbytes into the inode so when we | ||
376 | * replay the extents we've logged we get the right nbytes. | ||
377 | */ | ||
378 | if (inode_item) { | ||
379 | struct btrfs_inode_item *item; | ||
380 | u64 nbytes; | ||
381 | |||
382 | item = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
383 | struct btrfs_inode_item); | ||
384 | nbytes = btrfs_inode_nbytes(path->nodes[0], item); | ||
385 | item = btrfs_item_ptr(eb, slot, | ||
386 | struct btrfs_inode_item); | ||
387 | btrfs_set_inode_nbytes(eb, item, nbytes); | ||
388 | } | ||
389 | } else if (inode_item) { | ||
390 | struct btrfs_inode_item *item; | ||
391 | |||
392 | /* | ||
393 | * New inode, set nbytes to 0 so that the nbytes comes out | ||
394 | * properly when we replay the extents. | ||
395 | */ | ||
396 | item = btrfs_item_ptr(eb, slot, struct btrfs_inode_item); | ||
397 | btrfs_set_inode_nbytes(eb, item, 0); | ||
371 | } | 398 | } |
372 | insert: | 399 | insert: |
373 | btrfs_release_path(path); | 400 | btrfs_release_path(path); |
@@ -485,10 +512,9 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | |||
485 | struct btrfs_key *key) | 512 | struct btrfs_key *key) |
486 | { | 513 | { |
487 | int found_type; | 514 | int found_type; |
488 | u64 mask = root->sectorsize - 1; | ||
489 | u64 extent_end; | 515 | u64 extent_end; |
490 | u64 start = key->offset; | 516 | u64 start = key->offset; |
491 | u64 saved_nbytes; | 517 | u64 nbytes = 0; |
492 | struct btrfs_file_extent_item *item; | 518 | struct btrfs_file_extent_item *item; |
493 | struct inode *inode = NULL; | 519 | struct inode *inode = NULL; |
494 | unsigned long size; | 520 | unsigned long size; |
@@ -498,11 +524,20 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | |||
498 | found_type = btrfs_file_extent_type(eb, item); | 524 | found_type = btrfs_file_extent_type(eb, item); |
499 | 525 | ||
500 | if (found_type == BTRFS_FILE_EXTENT_REG || | 526 | if (found_type == BTRFS_FILE_EXTENT_REG || |
501 | found_type == BTRFS_FILE_EXTENT_PREALLOC) | 527 | found_type == BTRFS_FILE_EXTENT_PREALLOC) { |
502 | extent_end = start + btrfs_file_extent_num_bytes(eb, item); | 528 | nbytes = btrfs_file_extent_num_bytes(eb, item); |
503 | else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | 529 | extent_end = start + nbytes; |
530 | |||
531 | /* | ||
532 | * We don't add to the inodes nbytes if we are prealloc or a | ||
533 | * hole. | ||
534 | */ | ||
535 | if (btrfs_file_extent_disk_bytenr(eb, item) == 0) | ||
536 | nbytes = 0; | ||
537 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | ||
504 | size = btrfs_file_extent_inline_len(eb, item); | 538 | size = btrfs_file_extent_inline_len(eb, item); |
505 | extent_end = (start + size + mask) & ~mask; | 539 | nbytes = btrfs_file_extent_ram_bytes(eb, item); |
540 | extent_end = ALIGN(start + size, root->sectorsize); | ||
506 | } else { | 541 | } else { |
507 | ret = 0; | 542 | ret = 0; |
508 | goto out; | 543 | goto out; |
@@ -550,7 +585,6 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | |||
550 | } | 585 | } |
551 | btrfs_release_path(path); | 586 | btrfs_release_path(path); |
552 | 587 | ||
553 | saved_nbytes = inode_get_bytes(inode); | ||
554 | /* drop any overlapping extents */ | 588 | /* drop any overlapping extents */ |
555 | ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1); | 589 | ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1); |
556 | BUG_ON(ret); | 590 | BUG_ON(ret); |
@@ -637,7 +671,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | |||
637 | BUG_ON(ret); | 671 | BUG_ON(ret); |
638 | } | 672 | } |
639 | 673 | ||
640 | inode_set_bytes(inode, saved_nbytes); | 674 | inode_add_bytes(inode, nbytes); |
641 | ret = btrfs_update_inode(trans, root, inode); | 675 | ret = btrfs_update_inode(trans, root, inode); |
642 | out: | 676 | out: |
643 | if (inode) | 677 | if (inode) |
@@ -1384,7 +1418,10 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans, | |||
1384 | 1418 | ||
1385 | btrfs_release_path(path); | 1419 | btrfs_release_path(path); |
1386 | if (ret == 0) { | 1420 | if (ret == 0) { |
1387 | btrfs_inc_nlink(inode); | 1421 | if (!inode->i_nlink) |
1422 | set_nlink(inode, 1); | ||
1423 | else | ||
1424 | btrfs_inc_nlink(inode); | ||
1388 | ret = btrfs_update_inode(trans, root, inode); | 1425 | ret = btrfs_update_inode(trans, root, inode); |
1389 | } else if (ret == -EEXIST) { | 1426 | } else if (ret == -EEXIST) { |
1390 | ret = 0; | 1427 | ret = 0; |
@@ -2281,6 +2318,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2281 | unsigned long log_transid = 0; | 2318 | unsigned long log_transid = 0; |
2282 | 2319 | ||
2283 | mutex_lock(&root->log_mutex); | 2320 | mutex_lock(&root->log_mutex); |
2321 | log_transid = root->log_transid; | ||
2284 | index1 = root->log_transid % 2; | 2322 | index1 = root->log_transid % 2; |
2285 | if (atomic_read(&root->log_commit[index1])) { | 2323 | if (atomic_read(&root->log_commit[index1])) { |
2286 | wait_log_commit(trans, root, root->log_transid); | 2324 | wait_log_commit(trans, root, root->log_transid); |
@@ -2308,11 +2346,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2308 | /* bail out if we need to do a full commit */ | 2346 | /* bail out if we need to do a full commit */ |
2309 | if (root->fs_info->last_trans_log_full_commit == trans->transid) { | 2347 | if (root->fs_info->last_trans_log_full_commit == trans->transid) { |
2310 | ret = -EAGAIN; | 2348 | ret = -EAGAIN; |
2349 | btrfs_free_logged_extents(log, log_transid); | ||
2311 | mutex_unlock(&root->log_mutex); | 2350 | mutex_unlock(&root->log_mutex); |
2312 | goto out; | 2351 | goto out; |
2313 | } | 2352 | } |
2314 | 2353 | ||
2315 | log_transid = root->log_transid; | ||
2316 | if (log_transid % 2 == 0) | 2354 | if (log_transid % 2 == 0) |
2317 | mark = EXTENT_DIRTY; | 2355 | mark = EXTENT_DIRTY; |
2318 | else | 2356 | else |
@@ -2324,6 +2362,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2324 | ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark); | 2362 | ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark); |
2325 | if (ret) { | 2363 | if (ret) { |
2326 | btrfs_abort_transaction(trans, root, ret); | 2364 | btrfs_abort_transaction(trans, root, ret); |
2365 | btrfs_free_logged_extents(log, log_transid); | ||
2327 | mutex_unlock(&root->log_mutex); | 2366 | mutex_unlock(&root->log_mutex); |
2328 | goto out; | 2367 | goto out; |
2329 | } | 2368 | } |
@@ -2363,6 +2402,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2363 | } | 2402 | } |
2364 | root->fs_info->last_trans_log_full_commit = trans->transid; | 2403 | root->fs_info->last_trans_log_full_commit = trans->transid; |
2365 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2404 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); |
2405 | btrfs_free_logged_extents(log, log_transid); | ||
2366 | mutex_unlock(&log_root_tree->log_mutex); | 2406 | mutex_unlock(&log_root_tree->log_mutex); |
2367 | ret = -EAGAIN; | 2407 | ret = -EAGAIN; |
2368 | goto out; | 2408 | goto out; |
@@ -2373,6 +2413,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2373 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2413 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); |
2374 | wait_log_commit(trans, log_root_tree, | 2414 | wait_log_commit(trans, log_root_tree, |
2375 | log_root_tree->log_transid); | 2415 | log_root_tree->log_transid); |
2416 | btrfs_free_logged_extents(log, log_transid); | ||
2376 | mutex_unlock(&log_root_tree->log_mutex); | 2417 | mutex_unlock(&log_root_tree->log_mutex); |
2377 | ret = 0; | 2418 | ret = 0; |
2378 | goto out; | 2419 | goto out; |
@@ -2392,6 +2433,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2392 | */ | 2433 | */ |
2393 | if (root->fs_info->last_trans_log_full_commit == trans->transid) { | 2434 | if (root->fs_info->last_trans_log_full_commit == trans->transid) { |
2394 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2435 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); |
2436 | btrfs_free_logged_extents(log, log_transid); | ||
2395 | mutex_unlock(&log_root_tree->log_mutex); | 2437 | mutex_unlock(&log_root_tree->log_mutex); |
2396 | ret = -EAGAIN; | 2438 | ret = -EAGAIN; |
2397 | goto out_wake_log_root; | 2439 | goto out_wake_log_root; |
@@ -2402,10 +2444,12 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2402 | EXTENT_DIRTY | EXTENT_NEW); | 2444 | EXTENT_DIRTY | EXTENT_NEW); |
2403 | if (ret) { | 2445 | if (ret) { |
2404 | btrfs_abort_transaction(trans, root, ret); | 2446 | btrfs_abort_transaction(trans, root, ret); |
2447 | btrfs_free_logged_extents(log, log_transid); | ||
2405 | mutex_unlock(&log_root_tree->log_mutex); | 2448 | mutex_unlock(&log_root_tree->log_mutex); |
2406 | goto out_wake_log_root; | 2449 | goto out_wake_log_root; |
2407 | } | 2450 | } |
2408 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); | 2451 | btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); |
2452 | btrfs_wait_logged_extents(log, log_transid); | ||
2409 | 2453 | ||
2410 | btrfs_set_super_log_root(root->fs_info->super_for_commit, | 2454 | btrfs_set_super_log_root(root->fs_info->super_for_commit, |
2411 | log_root_tree->node->start); | 2455 | log_root_tree->node->start); |
@@ -2461,8 +2505,10 @@ static void free_log_tree(struct btrfs_trans_handle *trans, | |||
2461 | .process_func = process_one_buffer | 2505 | .process_func = process_one_buffer |
2462 | }; | 2506 | }; |
2463 | 2507 | ||
2464 | ret = walk_log_tree(trans, log, &wc); | 2508 | if (trans) { |
2465 | BUG_ON(ret); | 2509 | ret = walk_log_tree(trans, log, &wc); |
2510 | BUG_ON(ret); | ||
2511 | } | ||
2466 | 2512 | ||
2467 | while (1) { | 2513 | while (1) { |
2468 | ret = find_first_extent_bit(&log->dirty_log_pages, | 2514 | ret = find_first_extent_bit(&log->dirty_log_pages, |
@@ -2475,6 +2521,14 @@ static void free_log_tree(struct btrfs_trans_handle *trans, | |||
2475 | EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS); | 2521 | EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS); |
2476 | } | 2522 | } |
2477 | 2523 | ||
2524 | /* | ||
2525 | * We may have short-circuited the log tree with the full commit logic | ||
2526 | * and left ordered extents on our list, so clear these out to keep us | ||
2527 | * from leaking inodes and memory. | ||
2528 | */ | ||
2529 | btrfs_free_logged_extents(log, 0); | ||
2530 | btrfs_free_logged_extents(log, 1); | ||
2531 | |||
2478 | free_extent_buffer(log->node); | 2532 | free_extent_buffer(log->node); |
2479 | kfree(log); | 2533 | kfree(log); |
2480 | } | 2534 | } |
@@ -2724,7 +2778,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans, | |||
2724 | path->keep_locks = 1; | 2778 | path->keep_locks = 1; |
2725 | 2779 | ||
2726 | ret = btrfs_search_forward(root, &min_key, &max_key, | 2780 | ret = btrfs_search_forward(root, &min_key, &max_key, |
2727 | path, 0, trans->transid); | 2781 | path, trans->transid); |
2728 | 2782 | ||
2729 | /* | 2783 | /* |
2730 | * we didn't find anything from this transaction, see if there | 2784 | * we didn't find anything from this transaction, see if there |
@@ -3271,16 +3325,21 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
3271 | struct btrfs_root *log = root->log_root; | 3325 | struct btrfs_root *log = root->log_root; |
3272 | struct btrfs_file_extent_item *fi; | 3326 | struct btrfs_file_extent_item *fi; |
3273 | struct extent_buffer *leaf; | 3327 | struct extent_buffer *leaf; |
3328 | struct btrfs_ordered_extent *ordered; | ||
3274 | struct list_head ordered_sums; | 3329 | struct list_head ordered_sums; |
3275 | struct btrfs_map_token token; | 3330 | struct btrfs_map_token token; |
3276 | struct btrfs_key key; | 3331 | struct btrfs_key key; |
3277 | u64 csum_offset = em->mod_start - em->start; | 3332 | u64 mod_start = em->mod_start; |
3278 | u64 csum_len = em->mod_len; | 3333 | u64 mod_len = em->mod_len; |
3334 | u64 csum_offset; | ||
3335 | u64 csum_len; | ||
3279 | u64 extent_offset = em->start - em->orig_start; | 3336 | u64 extent_offset = em->start - em->orig_start; |
3280 | u64 block_len; | 3337 | u64 block_len; |
3281 | int ret; | 3338 | int ret; |
3339 | int index = log->log_transid % 2; | ||
3282 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | 3340 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; |
3283 | 3341 | ||
3342 | insert: | ||
3284 | INIT_LIST_HEAD(&ordered_sums); | 3343 | INIT_LIST_HEAD(&ordered_sums); |
3285 | btrfs_init_map_token(&token); | 3344 | btrfs_init_map_token(&token); |
3286 | key.objectid = btrfs_ino(inode); | 3345 | key.objectid = btrfs_ino(inode); |
@@ -3296,6 +3355,23 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
3296 | leaf = path->nodes[0]; | 3355 | leaf = path->nodes[0]; |
3297 | fi = btrfs_item_ptr(leaf, path->slots[0], | 3356 | fi = btrfs_item_ptr(leaf, path->slots[0], |
3298 | struct btrfs_file_extent_item); | 3357 | struct btrfs_file_extent_item); |
3358 | |||
3359 | /* | ||
3360 | * If we are overwriting an inline extent with a real one then we need | ||
3361 | * to just delete the inline extent as it may not be large enough to | ||
3362 | * have the entire file_extent_item. | ||
3363 | */ | ||
3364 | if (ret && btrfs_token_file_extent_type(leaf, fi, &token) == | ||
3365 | BTRFS_FILE_EXTENT_INLINE) { | ||
3366 | ret = btrfs_del_item(trans, log, path); | ||
3367 | btrfs_release_path(path); | ||
3368 | if (ret) { | ||
3369 | path->really_keep_locks = 0; | ||
3370 | return ret; | ||
3371 | } | ||
3372 | goto insert; | ||
3373 | } | ||
3374 | |||
3299 | btrfs_set_token_file_extent_generation(leaf, fi, em->generation, | 3375 | btrfs_set_token_file_extent_generation(leaf, fi, em->generation, |
3300 | &token); | 3376 | &token); |
3301 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) { | 3377 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) { |
@@ -3362,6 +3438,92 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
3362 | csum_len = block_len; | 3438 | csum_len = block_len; |
3363 | } | 3439 | } |
3364 | 3440 | ||
3441 | /* | ||
3442 | * First check and see if our csums are on our outstanding ordered | ||
3443 | * extents. | ||
3444 | */ | ||
3445 | again: | ||
3446 | spin_lock_irq(&log->log_extents_lock[index]); | ||
3447 | list_for_each_entry(ordered, &log->logged_list[index], log_list) { | ||
3448 | struct btrfs_ordered_sum *sum; | ||
3449 | |||
3450 | if (!mod_len) | ||
3451 | break; | ||
3452 | |||
3453 | if (ordered->inode != inode) | ||
3454 | continue; | ||
3455 | |||
3456 | if (ordered->file_offset + ordered->len <= mod_start || | ||
3457 | mod_start + mod_len <= ordered->file_offset) | ||
3458 | continue; | ||
3459 | |||
3460 | /* | ||
3461 | * We are going to copy all the csums on this ordered extent, so | ||
3462 | * go ahead and adjust mod_start and mod_len in case this | ||
3463 | * ordered extent has already been logged. | ||
3464 | */ | ||
3465 | if (ordered->file_offset > mod_start) { | ||
3466 | if (ordered->file_offset + ordered->len >= | ||
3467 | mod_start + mod_len) | ||
3468 | mod_len = ordered->file_offset - mod_start; | ||
3469 | /* | ||
3470 | * If we have this case | ||
3471 | * | ||
3472 | * |--------- logged extent ---------| | ||
3473 | * |----- ordered extent ----| | ||
3474 | * | ||
3475 | * Just don't mess with mod_start and mod_len, we'll | ||
3476 | * just end up logging more csums than we need and it | ||
3477 | * will be ok. | ||
3478 | */ | ||
3479 | } else { | ||
3480 | if (ordered->file_offset + ordered->len < | ||
3481 | mod_start + mod_len) { | ||
3482 | mod_len = (mod_start + mod_len) - | ||
3483 | (ordered->file_offset + ordered->len); | ||
3484 | mod_start = ordered->file_offset + | ||
3485 | ordered->len; | ||
3486 | } else { | ||
3487 | mod_len = 0; | ||
3488 | } | ||
3489 | } | ||
3490 | |||
3491 | /* | ||
3492 | * To keep us from looping for the above case of an ordered | ||
3493 | * extent that falls inside of the logged extent. | ||
3494 | */ | ||
3495 | if (test_and_set_bit(BTRFS_ORDERED_LOGGED_CSUM, | ||
3496 | &ordered->flags)) | ||
3497 | continue; | ||
3498 | atomic_inc(&ordered->refs); | ||
3499 | spin_unlock_irq(&log->log_extents_lock[index]); | ||
3500 | /* | ||
3501 | * we've dropped the lock, we must either break or | ||
3502 | * start over after this. | ||
3503 | */ | ||
3504 | |||
3505 | wait_event(ordered->wait, ordered->csum_bytes_left == 0); | ||
3506 | |||
3507 | list_for_each_entry(sum, &ordered->list, list) { | ||
3508 | ret = btrfs_csum_file_blocks(trans, log, sum); | ||
3509 | if (ret) { | ||
3510 | btrfs_put_ordered_extent(ordered); | ||
3511 | goto unlocked; | ||
3512 | } | ||
3513 | } | ||
3514 | btrfs_put_ordered_extent(ordered); | ||
3515 | goto again; | ||
3516 | |||
3517 | } | ||
3518 | spin_unlock_irq(&log->log_extents_lock[index]); | ||
3519 | unlocked: | ||
3520 | |||
3521 | if (!mod_len || ret) | ||
3522 | return ret; | ||
3523 | |||
3524 | csum_offset = mod_start - em->start; | ||
3525 | csum_len = mod_len; | ||
3526 | |||
3365 | /* block start is already adjusted for the file extent offset. */ | 3527 | /* block start is already adjusted for the file extent offset. */ |
3366 | ret = btrfs_lookup_csums_range(log->fs_info->csum_root, | 3528 | ret = btrfs_lookup_csums_range(log->fs_info->csum_root, |
3367 | em->block_start + csum_offset, | 3529 | em->block_start + csum_offset, |
@@ -3393,6 +3555,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | |||
3393 | struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; | 3555 | struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; |
3394 | u64 test_gen; | 3556 | u64 test_gen; |
3395 | int ret = 0; | 3557 | int ret = 0; |
3558 | int num = 0; | ||
3396 | 3559 | ||
3397 | INIT_LIST_HEAD(&extents); | 3560 | INIT_LIST_HEAD(&extents); |
3398 | 3561 | ||
@@ -3401,16 +3564,31 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | |||
3401 | 3564 | ||
3402 | list_for_each_entry_safe(em, n, &tree->modified_extents, list) { | 3565 | list_for_each_entry_safe(em, n, &tree->modified_extents, list) { |
3403 | list_del_init(&em->list); | 3566 | list_del_init(&em->list); |
3567 | |||
3568 | /* | ||
3569 | * Just an arbitrary number, this can be really CPU intensive | ||
3570 | * once we start getting a lot of extents, and really once we | ||
3571 | * have a bunch of extents we just want to commit since it will | ||
3572 | * be faster. | ||
3573 | */ | ||
3574 | if (++num > 32768) { | ||
3575 | list_del_init(&tree->modified_extents); | ||
3576 | ret = -EFBIG; | ||
3577 | goto process; | ||
3578 | } | ||
3579 | |||
3404 | if (em->generation <= test_gen) | 3580 | if (em->generation <= test_gen) |
3405 | continue; | 3581 | continue; |
3406 | /* Need a ref to keep it from getting evicted from cache */ | 3582 | /* Need a ref to keep it from getting evicted from cache */ |
3407 | atomic_inc(&em->refs); | 3583 | atomic_inc(&em->refs); |
3408 | set_bit(EXTENT_FLAG_LOGGING, &em->flags); | 3584 | set_bit(EXTENT_FLAG_LOGGING, &em->flags); |
3409 | list_add_tail(&em->list, &extents); | 3585 | list_add_tail(&em->list, &extents); |
3586 | num++; | ||
3410 | } | 3587 | } |
3411 | 3588 | ||
3412 | list_sort(NULL, &extents, extent_cmp); | 3589 | list_sort(NULL, &extents, extent_cmp); |
3413 | 3590 | ||
3591 | process: | ||
3414 | while (!list_empty(&extents)) { | 3592 | while (!list_empty(&extents)) { |
3415 | em = list_entry(extents.next, struct extent_map, list); | 3593 | em = list_entry(extents.next, struct extent_map, list); |
3416 | 3594 | ||
@@ -3513,6 +3691,8 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
3513 | 3691 | ||
3514 | mutex_lock(&BTRFS_I(inode)->log_mutex); | 3692 | mutex_lock(&BTRFS_I(inode)->log_mutex); |
3515 | 3693 | ||
3694 | btrfs_get_logged_extents(log, inode); | ||
3695 | |||
3516 | /* | 3696 | /* |
3517 | * a brute force approach to making sure we get the most uptodate | 3697 | * a brute force approach to making sure we get the most uptodate |
3518 | * copies of everything. | 3698 | * copies of everything. |
@@ -3558,7 +3738,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
3558 | while (1) { | 3738 | while (1) { |
3559 | ins_nr = 0; | 3739 | ins_nr = 0; |
3560 | ret = btrfs_search_forward(root, &min_key, &max_key, | 3740 | ret = btrfs_search_forward(root, &min_key, &max_key, |
3561 | path, 0, trans->transid); | 3741 | path, trans->transid); |
3562 | if (ret != 0) | 3742 | if (ret != 0) |
3563 | break; | 3743 | break; |
3564 | again: | 3744 | again: |
@@ -3656,6 +3836,8 @@ log_extents: | |||
3656 | BTRFS_I(inode)->logged_trans = trans->transid; | 3836 | BTRFS_I(inode)->logged_trans = trans->transid; |
3657 | BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans; | 3837 | BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans; |
3658 | out_unlock: | 3838 | out_unlock: |
3839 | if (err) | ||
3840 | btrfs_free_logged_extents(log, log->log_transid); | ||
3659 | mutex_unlock(&BTRFS_I(inode)->log_mutex); | 3841 | mutex_unlock(&BTRFS_I(inode)->log_mutex); |
3660 | 3842 | ||
3661 | btrfs_free_path(path); | 3843 | btrfs_free_path(path); |
@@ -3822,7 +4004,6 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
3822 | end_trans: | 4004 | end_trans: |
3823 | dput(old_parent); | 4005 | dput(old_parent); |
3824 | if (ret < 0) { | 4006 | if (ret < 0) { |
3825 | WARN_ON(ret != -ENOSPC); | ||
3826 | root->fs_info->last_trans_log_full_commit = trans->transid; | 4007 | root->fs_info->last_trans_log_full_commit = trans->transid; |
3827 | ret = 1; | 4008 | ret = 1; |
3828 | } | 4009 | } |