diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 121 |
1 files changed, 108 insertions, 13 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index c766649ad453..08469ec05850 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -934,24 +934,17 @@ static noinline int replay_one_csum(struct btrfs_trans_handle *trans, | |||
934 | unsigned long file_bytes; | 934 | unsigned long file_bytes; |
935 | struct btrfs_ordered_sum *sums; | 935 | struct btrfs_ordered_sum *sums; |
936 | struct btrfs_sector_sum *sector_sum; | 936 | struct btrfs_sector_sum *sector_sum; |
937 | struct inode *inode; | ||
938 | unsigned long ptr; | 937 | unsigned long ptr; |
939 | 938 | ||
940 | file_bytes = (item_size / csum_size) * root->sectorsize; | 939 | file_bytes = (item_size / csum_size) * root->sectorsize; |
941 | inode = read_one_inode(root, key->objectid); | ||
942 | if (!inode) { | ||
943 | return -EIO; | ||
944 | } | ||
945 | |||
946 | sums = kzalloc(btrfs_ordered_sum_size(root, file_bytes), GFP_NOFS); | 940 | sums = kzalloc(btrfs_ordered_sum_size(root, file_bytes), GFP_NOFS); |
947 | if (!sums) { | 941 | if (!sums) { |
948 | iput(inode); | ||
949 | return -ENOMEM; | 942 | return -ENOMEM; |
950 | } | 943 | } |
951 | 944 | ||
952 | INIT_LIST_HEAD(&sums->list); | 945 | INIT_LIST_HEAD(&sums->list); |
953 | sums->len = file_bytes; | 946 | sums->len = file_bytes; |
954 | sums->file_offset = key->offset; | 947 | sums->bytenr = key->offset; |
955 | 948 | ||
956 | /* | 949 | /* |
957 | * copy all the sums into the ordered sum struct | 950 | * copy all the sums into the ordered sum struct |
@@ -960,7 +953,7 @@ static noinline int replay_one_csum(struct btrfs_trans_handle *trans, | |||
960 | cur_offset = key->offset; | 953 | cur_offset = key->offset; |
961 | ptr = btrfs_item_ptr_offset(eb, slot); | 954 | ptr = btrfs_item_ptr_offset(eb, slot); |
962 | while(item_size > 0) { | 955 | while(item_size > 0) { |
963 | sector_sum->offset = cur_offset; | 956 | sector_sum->bytenr = cur_offset; |
964 | read_extent_buffer(eb, §or_sum->sum, ptr, csum_size); | 957 | read_extent_buffer(eb, §or_sum->sum, ptr, csum_size); |
965 | sector_sum++; | 958 | sector_sum++; |
966 | item_size -= csum_size; | 959 | item_size -= csum_size; |
@@ -969,11 +962,9 @@ static noinline int replay_one_csum(struct btrfs_trans_handle *trans, | |||
969 | } | 962 | } |
970 | 963 | ||
971 | /* let btrfs_csum_file_blocks add them into the file */ | 964 | /* let btrfs_csum_file_blocks add them into the file */ |
972 | ret = btrfs_csum_file_blocks(trans, root, inode, sums); | 965 | ret = btrfs_csum_file_blocks(trans, root->fs_info->csum_root, sums); |
973 | BUG_ON(ret); | 966 | BUG_ON(ret); |
974 | kfree(sums); | 967 | kfree(sums); |
975 | iput(inode); | ||
976 | |||
977 | return 0; | 968 | return 0; |
978 | } | 969 | } |
979 | /* | 970 | /* |
@@ -1670,7 +1661,7 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, | |||
1670 | ret = replay_one_extent(wc->trans, root, path, | 1661 | ret = replay_one_extent(wc->trans, root, path, |
1671 | eb, i, &key); | 1662 | eb, i, &key); |
1672 | BUG_ON(ret); | 1663 | BUG_ON(ret); |
1673 | } else if (key.type == BTRFS_CSUM_ITEM_KEY) { | 1664 | } else if (key.type == BTRFS_EXTENT_CSUM_KEY) { |
1674 | ret = replay_one_csum(wc->trans, root, path, | 1665 | ret = replay_one_csum(wc->trans, root, path, |
1675 | eb, i, &key); | 1666 | eb, i, &key); |
1676 | BUG_ON(ret); | 1667 | BUG_ON(ret); |
@@ -2466,6 +2457,85 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans, | |||
2466 | return 0; | 2457 | return 0; |
2467 | } | 2458 | } |
2468 | 2459 | ||
2460 | static noinline int copy_extent_csums(struct btrfs_trans_handle *trans, | ||
2461 | struct list_head *list, | ||
2462 | struct btrfs_root *root, | ||
2463 | u64 disk_bytenr, u64 len) | ||
2464 | { | ||
2465 | struct btrfs_ordered_sum *sums; | ||
2466 | struct btrfs_sector_sum *sector_sum; | ||
2467 | int ret; | ||
2468 | struct btrfs_path *path; | ||
2469 | struct btrfs_csum_item *item = NULL; | ||
2470 | u64 end = disk_bytenr + len; | ||
2471 | u64 item_start_offset = 0; | ||
2472 | u64 item_last_offset = 0; | ||
2473 | u32 diff; | ||
2474 | u32 sum; | ||
2475 | u16 csum_size = btrfs_super_csum_size(&root->fs_info->super_copy); | ||
2476 | |||
2477 | sums = kzalloc(btrfs_ordered_sum_size(root, len), GFP_NOFS); | ||
2478 | |||
2479 | sector_sum = sums->sums; | ||
2480 | sums->bytenr = disk_bytenr; | ||
2481 | sums->len = len; | ||
2482 | list_add_tail(&sums->list, list); | ||
2483 | |||
2484 | path = btrfs_alloc_path(); | ||
2485 | while(disk_bytenr < end) { | ||
2486 | if (!item || disk_bytenr < item_start_offset || | ||
2487 | disk_bytenr >= item_last_offset) { | ||
2488 | struct btrfs_key found_key; | ||
2489 | u32 item_size; | ||
2490 | |||
2491 | if (item) | ||
2492 | btrfs_release_path(root, path); | ||
2493 | item = btrfs_lookup_csum(NULL, root, path, | ||
2494 | disk_bytenr, 0); | ||
2495 | if (IS_ERR(item)) { | ||
2496 | ret = PTR_ERR(item); | ||
2497 | if (ret == -ENOENT || ret == -EFBIG) | ||
2498 | ret = 0; | ||
2499 | sum = 0; | ||
2500 | printk("log no csum found for byte %llu\n", | ||
2501 | (unsigned long long)disk_bytenr); | ||
2502 | item = NULL; | ||
2503 | btrfs_release_path(root, path); | ||
2504 | goto found; | ||
2505 | } | ||
2506 | btrfs_item_key_to_cpu(path->nodes[0], &found_key, | ||
2507 | path->slots[0]); | ||
2508 | |||
2509 | item_start_offset = found_key.offset; | ||
2510 | item_size = btrfs_item_size_nr(path->nodes[0], | ||
2511 | path->slots[0]); | ||
2512 | item_last_offset = item_start_offset + | ||
2513 | (item_size / csum_size) * | ||
2514 | root->sectorsize; | ||
2515 | item = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
2516 | struct btrfs_csum_item); | ||
2517 | } | ||
2518 | /* | ||
2519 | * this byte range must be able to fit inside | ||
2520 | * a single leaf so it will also fit inside a u32 | ||
2521 | */ | ||
2522 | diff = disk_bytenr - item_start_offset; | ||
2523 | diff = diff / root->sectorsize; | ||
2524 | diff = diff * csum_size; | ||
2525 | |||
2526 | read_extent_buffer(path->nodes[0], &sum, | ||
2527 | ((unsigned long)item) + diff, | ||
2528 | csum_size); | ||
2529 | found: | ||
2530 | sector_sum->bytenr = disk_bytenr; | ||
2531 | sector_sum->sum = sum; | ||
2532 | disk_bytenr += root->sectorsize; | ||
2533 | sector_sum++; | ||
2534 | } | ||
2535 | btrfs_free_path(path); | ||
2536 | return 0; | ||
2537 | } | ||
2538 | |||
2469 | static noinline int copy_items(struct btrfs_trans_handle *trans, | 2539 | static noinline int copy_items(struct btrfs_trans_handle *trans, |
2470 | struct btrfs_root *log, | 2540 | struct btrfs_root *log, |
2471 | struct btrfs_path *dst_path, | 2541 | struct btrfs_path *dst_path, |
@@ -2481,6 +2551,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
2481 | u32 *ins_sizes; | 2551 | u32 *ins_sizes; |
2482 | char *ins_data; | 2552 | char *ins_data; |
2483 | int i; | 2553 | int i; |
2554 | struct list_head ordered_sums; | ||
2555 | |||
2556 | INIT_LIST_HEAD(&ordered_sums); | ||
2484 | 2557 | ||
2485 | ins_data = kmalloc(nr * sizeof(struct btrfs_key) + | 2558 | ins_data = kmalloc(nr * sizeof(struct btrfs_key) + |
2486 | nr * sizeof(u32), GFP_NOFS); | 2559 | nr * sizeof(u32), GFP_NOFS); |
@@ -2535,6 +2608,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
2535 | extent); | 2608 | extent); |
2536 | u64 dl = btrfs_file_extent_disk_num_bytes(src, | 2609 | u64 dl = btrfs_file_extent_disk_num_bytes(src, |
2537 | extent); | 2610 | extent); |
2611 | u64 cs = btrfs_file_extent_offset(src, extent); | ||
2612 | u64 cl = btrfs_file_extent_num_bytes(src, | ||
2613 | extent);; | ||
2538 | /* ds == 0 is a hole */ | 2614 | /* ds == 0 is a hole */ |
2539 | if (ds != 0) { | 2615 | if (ds != 0) { |
2540 | ret = btrfs_inc_extent_ref(trans, log, | 2616 | ret = btrfs_inc_extent_ref(trans, log, |
@@ -2544,6 +2620,11 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
2544 | trans->transid, | 2620 | trans->transid, |
2545 | ins_keys[i].objectid); | 2621 | ins_keys[i].objectid); |
2546 | BUG_ON(ret); | 2622 | BUG_ON(ret); |
2623 | ret = copy_extent_csums(trans, | ||
2624 | &ordered_sums, | ||
2625 | log->fs_info->csum_root, | ||
2626 | ds + cs, cl); | ||
2627 | BUG_ON(ret); | ||
2547 | } | 2628 | } |
2548 | } | 2629 | } |
2549 | } | 2630 | } |
@@ -2553,6 +2634,20 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
2553 | btrfs_mark_buffer_dirty(dst_path->nodes[0]); | 2634 | btrfs_mark_buffer_dirty(dst_path->nodes[0]); |
2554 | btrfs_release_path(log, dst_path); | 2635 | btrfs_release_path(log, dst_path); |
2555 | kfree(ins_data); | 2636 | kfree(ins_data); |
2637 | |||
2638 | /* | ||
2639 | * we have to do this after the loop above to avoid changing the | ||
2640 | * log tree while trying to change the log tree. | ||
2641 | */ | ||
2642 | while(!list_empty(&ordered_sums)) { | ||
2643 | struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next, | ||
2644 | struct btrfs_ordered_sum, | ||
2645 | list); | ||
2646 | ret = btrfs_csum_file_blocks(trans, log, sums); | ||
2647 | BUG_ON(ret); | ||
2648 | list_del(&sums->list); | ||
2649 | kfree(sums); | ||
2650 | } | ||
2556 | return 0; | 2651 | return 0; |
2557 | } | 2652 | } |
2558 | 2653 | ||