diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/btrfs/ctree.c | 131 | ||||
| -rw-r--r-- | fs/btrfs/ctree.h | 13 | ||||
| -rw-r--r-- | fs/btrfs/extent-tree.c | 6 | ||||
| -rw-r--r-- | fs/btrfs/file-item.c | 226 |
4 files changed, 335 insertions, 41 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 19c0dd33b1e..c0c95cccbb5 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
| @@ -1512,7 +1512,8 @@ cow_done: | |||
| 1512 | if (ret && slot > 0) | 1512 | if (ret && slot > 0) |
| 1513 | slot -= 1; | 1513 | slot -= 1; |
| 1514 | p->slots[level] = slot; | 1514 | p->slots[level] = slot; |
| 1515 | if (ins_len > 0 && btrfs_header_nritems(b) >= | 1515 | if ((p->search_for_split || ins_len > 0) && |
| 1516 | btrfs_header_nritems(b) >= | ||
| 1516 | BTRFS_NODEPTRS_PER_BLOCK(root) - 3) { | 1517 | BTRFS_NODEPTRS_PER_BLOCK(root) - 3) { |
| 1517 | int sret = split_node(trans, root, p, level); | 1518 | int sret = split_node(trans, root, p, level); |
| 1518 | BUG_ON(sret > 0); | 1519 | BUG_ON(sret > 0); |
| @@ -1596,7 +1597,8 @@ cow_done: | |||
| 1596 | goto done; | 1597 | goto done; |
| 1597 | } | 1598 | } |
| 1598 | } | 1599 | } |
| 1599 | unlock_up(p, level, lowest_unlock); | 1600 | if (!p->search_for_split) |
| 1601 | unlock_up(p, level, lowest_unlock); | ||
| 1600 | goto done; | 1602 | goto done; |
| 1601 | } | 1603 | } |
| 1602 | } | 1604 | } |
| @@ -2636,11 +2638,11 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans, | |||
| 2636 | int num_doubles = 0; | 2638 | int num_doubles = 0; |
| 2637 | struct btrfs_disk_key disk_key; | 2639 | struct btrfs_disk_key disk_key; |
| 2638 | 2640 | ||
| 2639 | if (extend) | 2641 | if (extend && data_size) |
| 2640 | space_needed = data_size; | 2642 | space_needed = data_size; |
| 2641 | 2643 | ||
| 2642 | /* first try to make some room by pushing left and right */ | 2644 | /* first try to make some room by pushing left and right */ |
| 2643 | if (ins_key->type != BTRFS_DIR_ITEM_KEY) { | 2645 | if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) { |
| 2644 | wret = push_leaf_right(trans, root, path, data_size, 0); | 2646 | wret = push_leaf_right(trans, root, path, data_size, 0); |
| 2645 | if (wret < 0) { | 2647 | if (wret < 0) { |
| 2646 | return wret; | 2648 | return wret; |
| @@ -2721,7 +2723,7 @@ again: | |||
| 2721 | } else { | 2723 | } else { |
| 2722 | if (leaf_space_used(l, 0, mid + 1) + space_needed > | 2724 | if (leaf_space_used(l, 0, mid + 1) + space_needed > |
| 2723 | BTRFS_LEAF_DATA_SIZE(root)) { | 2725 | BTRFS_LEAF_DATA_SIZE(root)) { |
| 2724 | if (!extend && slot == 0) { | 2726 | if (!extend && data_size && slot == 0) { |
| 2725 | btrfs_cpu_key_to_disk(&disk_key, ins_key); | 2727 | btrfs_cpu_key_to_disk(&disk_key, ins_key); |
| 2726 | btrfs_set_header_nritems(right, 0); | 2728 | btrfs_set_header_nritems(right, 0); |
| 2727 | wret = insert_ptr(trans, root, path, | 2729 | wret = insert_ptr(trans, root, path, |
| @@ -2742,7 +2744,7 @@ again: | |||
| 2742 | } | 2744 | } |
| 2743 | btrfs_mark_buffer_dirty(right); | 2745 | btrfs_mark_buffer_dirty(right); |
| 2744 | return ret; | 2746 | return ret; |
| 2745 | } else if (extend && slot == 0) { | 2747 | } else if ((extend || !data_size) && slot == 0) { |
| 2746 | mid = 1; | 2748 | mid = 1; |
| 2747 | } else { | 2749 | } else { |
| 2748 | mid = slot; | 2750 | mid = slot; |
| @@ -2828,6 +2830,123 @@ again: | |||
| 2828 | } | 2830 | } |
| 2829 | 2831 | ||
| 2830 | /* | 2832 | /* |
| 2833 | * This function splits a single item into two items, | ||
| 2834 | * giving 'new_key' to the new item and splitting the | ||
| 2835 | * old one at split_offset (from the start of the item). | ||
| 2836 | * | ||
| 2837 | * The path may be released by this operation. After | ||
| 2838 | * the split, the path is pointing to the old item. The | ||
| 2839 | * new item is going to be in the same node as the old one. | ||
| 2840 | * | ||
| 2841 | * Note, the item being split must be smaller enough to live alone on | ||
| 2842 | * a tree block with room for one extra struct btrfs_item | ||
| 2843 | * | ||
| 2844 | * This allows us to split the item in place, keeping a lock on the | ||
| 2845 | * leaf the entire time. | ||
| 2846 | */ | ||
| 2847 | int btrfs_split_item(struct btrfs_trans_handle *trans, | ||
| 2848 | struct btrfs_root *root, | ||
| 2849 | struct btrfs_path *path, | ||
| 2850 | struct btrfs_key *new_key, | ||
| 2851 | unsigned long split_offset) | ||
| 2852 | { | ||
| 2853 | u32 item_size; | ||
| 2854 | struct extent_buffer *leaf; | ||
| 2855 | struct btrfs_key orig_key; | ||
| 2856 | struct btrfs_item *item; | ||
| 2857 | struct btrfs_item *new_item; | ||
| 2858 | int ret = 0; | ||
| 2859 | int slot; | ||
| 2860 | u32 nritems; | ||
| 2861 | u32 orig_offset; | ||
| 2862 | struct btrfs_disk_key disk_key; | ||
| 2863 | char *buf; | ||
| 2864 | |||
| 2865 | leaf = path->nodes[0]; | ||
| 2866 | btrfs_item_key_to_cpu(leaf, &orig_key, path->slots[0]); | ||
| 2867 | if (btrfs_leaf_free_space(root, leaf) >= sizeof(struct btrfs_item)) | ||
| 2868 | goto split; | ||
| 2869 | |||
| 2870 | item_size = btrfs_item_size_nr(leaf, path->slots[0]); | ||
| 2871 | btrfs_release_path(root, path); | ||
| 2872 | |||
| 2873 | path->search_for_split = 1; | ||
| 2874 | path->keep_locks = 1; | ||
| 2875 | |||
| 2876 | ret = btrfs_search_slot(trans, root, &orig_key, path, 0, 1); | ||
| 2877 | path->search_for_split = 0; | ||
| 2878 | |||
| 2879 | /* if our item isn't there or got smaller, return now */ | ||
| 2880 | if (ret != 0 || item_size != btrfs_item_size_nr(path->nodes[0], | ||
| 2881 | path->slots[0])) { | ||
| 2882 | path->keep_locks = 0; | ||
| 2883 | return -EAGAIN; | ||
| 2884 | } | ||
| 2885 | |||
| 2886 | ret = split_leaf(trans, root, &orig_key, path, 0, 0); | ||
| 2887 | path->keep_locks = 0; | ||
| 2888 | BUG_ON(ret); | ||
| 2889 | |||
| 2890 | BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item)); | ||
| 2891 | leaf = path->nodes[0]; | ||
| 2892 | |||
| 2893 | split: | ||
| 2894 | item = btrfs_item_nr(leaf, path->slots[0]); | ||
| 2895 | orig_offset = btrfs_item_offset(leaf, item); | ||
| 2896 | item_size = btrfs_item_size(leaf, item); | ||
| 2897 | |||
| 2898 | |||
| 2899 | buf = kmalloc(item_size, GFP_NOFS); | ||
| 2900 | read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, | ||
| 2901 | path->slots[0]), item_size); | ||
| 2902 | slot = path->slots[0] + 1; | ||
| 2903 | leaf = path->nodes[0]; | ||
| 2904 | |||
| 2905 | nritems = btrfs_header_nritems(leaf); | ||
| 2906 | |||
| 2907 | if (slot != nritems) { | ||
| 2908 | /* shift the items */ | ||
| 2909 | memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1), | ||
| 2910 | btrfs_item_nr_offset(slot), | ||
| 2911 | (nritems - slot) * sizeof(struct btrfs_item)); | ||
| 2912 | |||
| 2913 | } | ||
| 2914 | |||
| 2915 | btrfs_cpu_key_to_disk(&disk_key, new_key); | ||
| 2916 | btrfs_set_item_key(leaf, &disk_key, slot); | ||
| 2917 | |||
| 2918 | new_item = btrfs_item_nr(leaf, slot); | ||
| 2919 | |||
| 2920 | btrfs_set_item_offset(leaf, new_item, orig_offset); | ||
| 2921 | btrfs_set_item_size(leaf, new_item, item_size - split_offset); | ||
| 2922 | |||
| 2923 | btrfs_set_item_offset(leaf, item, | ||
| 2924 | orig_offset + item_size - split_offset); | ||
| 2925 | btrfs_set_item_size(leaf, item, split_offset); | ||
| 2926 | |||
| 2927 | btrfs_set_header_nritems(leaf, nritems + 1); | ||
| 2928 | |||
| 2929 | /* write the data for the start of the original item */ | ||
| 2930 | write_extent_buffer(leaf, buf, | ||
| 2931 | btrfs_item_ptr_offset(leaf, path->slots[0]), | ||
| 2932 | split_offset); | ||
| 2933 | |||
| 2934 | /* write the data for the new item */ | ||
| 2935 | write_extent_buffer(leaf, buf + split_offset, | ||
| 2936 | btrfs_item_ptr_offset(leaf, slot), | ||
| 2937 | item_size - split_offset); | ||
| 2938 | btrfs_mark_buffer_dirty(leaf); | ||
| 2939 | |||
| 2940 | ret = 0; | ||
| 2941 | if (btrfs_leaf_free_space(root, leaf) < 0) { | ||
| 2942 | btrfs_print_leaf(root, leaf); | ||
| 2943 | BUG(); | ||
| 2944 | } | ||
| 2945 | kfree(buf); | ||
| 2946 | return ret; | ||
| 2947 | } | ||
| 2948 | |||
| 2949 | /* | ||
| 2831 | * make the item pointed to by the path smaller. new_size indicates | 2950 | * make the item pointed to by the path smaller. new_size indicates |
| 2832 | * how small to make it, and from_end tells us if we just chop bytes | 2951 | * how small to make it, and from_end tells us if we just chop bytes |
| 2833 | * off the end of the item or if we shift the item to chop bytes off | 2952 | * off the end of the item or if we shift the item to chop bytes off |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index f72b4381934..5b0c79d22c0 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -409,6 +409,12 @@ struct btrfs_path { | |||
| 409 | int keep_locks; | 409 | int keep_locks; |
| 410 | int skip_locking; | 410 | int skip_locking; |
| 411 | int lowest_level; | 411 | int lowest_level; |
| 412 | |||
| 413 | /* | ||
| 414 | * set by btrfs_split_item, tells search_slot to keep all locks | ||
| 415 | * and to force calls to keep space in the nodes | ||
| 416 | */ | ||
| 417 | int search_for_split; | ||
| 412 | }; | 418 | }; |
| 413 | 419 | ||
| 414 | /* | 420 | /* |
| @@ -1816,6 +1822,11 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans, | |||
| 1816 | struct btrfs_root *root, | 1822 | struct btrfs_root *root, |
| 1817 | struct btrfs_path *path, | 1823 | struct btrfs_path *path, |
| 1818 | u32 new_size, int from_end); | 1824 | u32 new_size, int from_end); |
| 1825 | int btrfs_split_item(struct btrfs_trans_handle *trans, | ||
| 1826 | struct btrfs_root *root, | ||
| 1827 | struct btrfs_path *path, | ||
| 1828 | struct btrfs_key *new_key, | ||
| 1829 | unsigned long split_offset); | ||
| 1819 | int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root | 1830 | int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root |
| 1820 | *root, struct btrfs_key *key, struct btrfs_path *p, int | 1831 | *root, struct btrfs_key *key, struct btrfs_path *p, int |
| 1821 | ins_len, int cow); | 1832 | ins_len, int cow); |
| @@ -1953,6 +1964,8 @@ int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root | |||
| 1953 | struct btrfs_key *location, int mod); | 1964 | struct btrfs_key *location, int mod); |
| 1954 | 1965 | ||
| 1955 | /* file-item.c */ | 1966 | /* file-item.c */ |
| 1967 | int btrfs_del_csums(struct btrfs_trans_handle *trans, | ||
| 1968 | struct btrfs_root *root, u64 bytenr, u64 len); | ||
| 1956 | int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, | 1969 | int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, |
| 1957 | struct bio *bio, u32 *dst); | 1970 | struct bio *bio, u32 *dst); |
| 1958 | int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, | 1971 | int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 803647bc840..cc74316dc42 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
| @@ -2484,7 +2484,6 @@ static int __free_extent(struct btrfs_trans_handle *trans, | |||
| 2484 | mark_free = 1; | 2484 | mark_free = 1; |
| 2485 | BUG_ON(ret < 0); | 2485 | BUG_ON(ret < 0); |
| 2486 | } | 2486 | } |
| 2487 | |||
| 2488 | /* block accounting for super block */ | 2487 | /* block accounting for super block */ |
| 2489 | spin_lock_irq(&info->delalloc_lock); | 2488 | spin_lock_irq(&info->delalloc_lock); |
| 2490 | super_used = btrfs_super_bytes_used(&info->super_copy); | 2489 | super_used = btrfs_super_bytes_used(&info->super_copy); |
| @@ -2504,6 +2503,11 @@ static int __free_extent(struct btrfs_trans_handle *trans, | |||
| 2504 | mark_free); | 2503 | mark_free); |
| 2505 | BUG_ON(ret); | 2504 | BUG_ON(ret); |
| 2506 | 2505 | ||
| 2506 | if (owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) { | ||
| 2507 | ret = btrfs_del_csums(trans, root, bytenr, num_bytes); | ||
| 2508 | BUG_ON(ret); | ||
| 2509 | } | ||
| 2510 | |||
| 2507 | #ifdef BIO_RW_DISCARD | 2511 | #ifdef BIO_RW_DISCARD |
| 2508 | /* Tell the block device(s) that the sectors can be discarded */ | 2512 | /* Tell the block device(s) that the sectors can be discarded */ |
| 2509 | ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, | 2513 | ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, |
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index a3ad2ce0011..3ebef871ee6 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
| @@ -310,6 +310,179 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | |||
| 310 | return 0; | 310 | return 0; |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | /* | ||
| 314 | * helper function for csum removal, this expects the | ||
| 315 | * key to describe the csum pointed to by the path, and it expects | ||
| 316 | * the csum to overlap the range [bytenr, len] | ||
| 317 | * | ||
| 318 | * The csum should not be entirely contained in the range and the | ||
| 319 | * range should not be entirely contained in the csum. | ||
| 320 | * | ||
| 321 | * This calls btrfs_truncate_item with the correct args based on the | ||
| 322 | * overlap, and fixes up the key as required. | ||
| 323 | */ | ||
| 324 | static noinline int truncate_one_csum(struct btrfs_trans_handle *trans, | ||
| 325 | struct btrfs_root *root, | ||
| 326 | struct btrfs_path *path, | ||
| 327 | struct btrfs_key *key, | ||
| 328 | u64 bytenr, u64 len) | ||
| 329 | { | ||
| 330 | struct extent_buffer *leaf; | ||
| 331 | u16 csum_size = | ||
| 332 | btrfs_super_csum_size(&root->fs_info->super_copy); | ||
| 333 | u64 csum_end; | ||
| 334 | u64 end_byte = bytenr + len; | ||
| 335 | u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits; | ||
| 336 | int ret; | ||
| 337 | |||
| 338 | leaf = path->nodes[0]; | ||
| 339 | csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; | ||
| 340 | csum_end <<= root->fs_info->sb->s_blocksize_bits; | ||
| 341 | csum_end += key->offset; | ||
| 342 | |||
| 343 | if (key->offset < bytenr && csum_end <= end_byte) { | ||
| 344 | /* | ||
| 345 | * [ bytenr - len ] | ||
| 346 | * [ ] | ||
| 347 | * [csum ] | ||
| 348 | * A simple truncate off the end of the item | ||
| 349 | */ | ||
| 350 | u32 new_size = (bytenr - key->offset) >> blocksize_bits; | ||
| 351 | new_size *= csum_size; | ||
| 352 | ret = btrfs_truncate_item(trans, root, path, new_size, 1); | ||
| 353 | BUG_ON(ret); | ||
| 354 | } else if (key->offset >= bytenr && csum_end > end_byte && | ||
| 355 | end_byte > key->offset) { | ||
| 356 | /* | ||
| 357 | * [ bytenr - len ] | ||
| 358 | * [ ] | ||
| 359 | * [csum ] | ||
| 360 | * we need to truncate from the beginning of the csum | ||
| 361 | */ | ||
| 362 | u32 new_size = (csum_end - end_byte) >> blocksize_bits; | ||
| 363 | new_size *= csum_size; | ||
| 364 | |||
| 365 | ret = btrfs_truncate_item(trans, root, path, new_size, 0); | ||
| 366 | BUG_ON(ret); | ||
| 367 | |||
| 368 | key->offset = end_byte; | ||
| 369 | ret = btrfs_set_item_key_safe(trans, root, path, key); | ||
| 370 | BUG_ON(ret); | ||
| 371 | } else { | ||
| 372 | BUG(); | ||
| 373 | } | ||
| 374 | return 0; | ||
| 375 | } | ||
| 376 | |||
| 377 | /* | ||
| 378 | * deletes the csum items from the csum tree for a given | ||
| 379 | * range of bytes. | ||
| 380 | */ | ||
| 381 | int btrfs_del_csums(struct btrfs_trans_handle *trans, | ||
| 382 | struct btrfs_root *root, u64 bytenr, u64 len) | ||
| 383 | { | ||
| 384 | struct btrfs_path *path; | ||
| 385 | struct btrfs_key key; | ||
| 386 | u64 end_byte = bytenr + len; | ||
| 387 | u64 csum_end; | ||
| 388 | struct extent_buffer *leaf; | ||
| 389 | int ret; | ||
| 390 | u16 csum_size = | ||
| 391 | btrfs_super_csum_size(&root->fs_info->super_copy); | ||
| 392 | int blocksize_bits = root->fs_info->sb->s_blocksize_bits; | ||
| 393 | |||
| 394 | root = root->fs_info->csum_root; | ||
| 395 | |||
| 396 | path = btrfs_alloc_path(); | ||
| 397 | |||
| 398 | while(1) { | ||
| 399 | key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; | ||
| 400 | key.offset = end_byte - 1; | ||
| 401 | key.type = BTRFS_EXTENT_CSUM_KEY; | ||
| 402 | |||
| 403 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | ||
| 404 | if (ret > 0) { | ||
| 405 | if (path->slots[0] == 0) | ||
| 406 | goto out; | ||
| 407 | path->slots[0]--; | ||
| 408 | } | ||
| 409 | leaf = path->nodes[0]; | ||
| 410 | btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); | ||
| 411 | |||
| 412 | if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || | ||
| 413 | key.type != BTRFS_EXTENT_CSUM_KEY) { | ||
| 414 | break; | ||
| 415 | } | ||
| 416 | |||
| 417 | if (key.offset >= end_byte) | ||
| 418 | break; | ||
| 419 | |||
| 420 | csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; | ||
| 421 | csum_end <<= blocksize_bits; | ||
| 422 | csum_end += key.offset; | ||
| 423 | |||
| 424 | /* this csum ends before we start, we're done */ | ||
| 425 | if (csum_end <= bytenr) | ||
| 426 | break; | ||
| 427 | |||
| 428 | /* delete the entire item, it is inside our range */ | ||
| 429 | if (key.offset >= bytenr && csum_end <= end_byte) { | ||
| 430 | ret = btrfs_del_item(trans, root, path); | ||
| 431 | BUG_ON(ret); | ||
| 432 | } else if (key.offset < bytenr && csum_end > end_byte) { | ||
| 433 | unsigned long offset; | ||
| 434 | unsigned long shift_len; | ||
| 435 | unsigned long item_offset; | ||
| 436 | /* | ||
| 437 | * [ bytenr - len ] | ||
| 438 | * [csum ] | ||
| 439 | * | ||
| 440 | * Our bytes are in the middle of the csum, | ||
| 441 | * we need to split this item and insert a new one. | ||
| 442 | * | ||
| 443 | * But we can't drop the path because the | ||
| 444 | * csum could change, get removed, extended etc. | ||
| 445 | * | ||
| 446 | * The trick here is the max size of a csum item leaves | ||
| 447 | * enough room in the tree block for a single | ||
| 448 | * item header. So, we split the item in place, | ||
| 449 | * adding a new header pointing to the existing | ||
| 450 | * bytes. Then we loop around again and we have | ||
| 451 | * a nicely formed csum item that we can neatly | ||
| 452 | * truncate. | ||
| 453 | */ | ||
| 454 | offset = (bytenr - key.offset) >> blocksize_bits; | ||
| 455 | offset *= csum_size; | ||
| 456 | |||
| 457 | shift_len = (len >> blocksize_bits) * csum_size; | ||
| 458 | |||
| 459 | item_offset = btrfs_item_ptr_offset(leaf, | ||
| 460 | path->slots[0]); | ||
| 461 | |||
| 462 | memset_extent_buffer(leaf, 0, item_offset + offset, | ||
| 463 | shift_len); | ||
| 464 | key.offset = bytenr; | ||
| 465 | |||
| 466 | /* | ||
| 467 | * btrfs_split_item returns -EAGAIN when the | ||
| 468 | * item changed size or key | ||
| 469 | */ | ||
| 470 | ret = btrfs_split_item(trans, root, path, &key, offset); | ||
| 471 | BUG_ON(ret && ret != -EAGAIN); | ||
| 472 | |||
| 473 | key.offset = end_byte - 1; | ||
| 474 | } else { | ||
| 475 | ret = truncate_one_csum(trans, root, path, | ||
| 476 | &key, bytenr, len); | ||
| 477 | BUG_ON(ret); | ||
| 478 | } | ||
| 479 | btrfs_release_path(root, path); | ||
| 480 | } | ||
| 481 | out: | ||
| 482 | btrfs_free_path(path); | ||
| 483 | return 0; | ||
| 484 | } | ||
| 485 | |||
| 313 | int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, | 486 | int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, |
| 314 | struct btrfs_root *root, | 487 | struct btrfs_root *root, |
| 315 | struct btrfs_ordered_sum *sums) | 488 | struct btrfs_ordered_sum *sums) |
| @@ -396,28 +569,40 @@ again: | |||
| 396 | csum_size, 1); | 569 | csum_size, 1); |
| 397 | if (ret < 0) | 570 | if (ret < 0) |
| 398 | goto fail_unlock; | 571 | goto fail_unlock; |
| 399 | if (ret == 0) { | 572 | |
| 400 | BUG(); | 573 | if (ret > 0) { |
| 401 | } | 574 | if (path->slots[0] == 0) |
| 402 | if (path->slots[0] == 0) { | 575 | goto insert; |
| 403 | goto insert; | 576 | path->slots[0]--; |
| 404 | } | 577 | } |
| 405 | path->slots[0]--; | 578 | |
| 406 | leaf = path->nodes[0]; | 579 | leaf = path->nodes[0]; |
| 407 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | 580 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
| 408 | csum_offset = (bytenr - found_key.offset) >> | 581 | csum_offset = (bytenr - found_key.offset) >> |
| 409 | root->fs_info->sb->s_blocksize_bits; | 582 | root->fs_info->sb->s_blocksize_bits; |
| 583 | |||
| 410 | if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY || | 584 | if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY || |
| 411 | found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || | 585 | found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || |
| 412 | csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { | 586 | csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { |
| 413 | goto insert; | 587 | goto insert; |
| 414 | } | 588 | } |
| 589 | |||
| 415 | if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) / | 590 | if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) / |
| 416 | csum_size) { | 591 | csum_size) { |
| 417 | u32 diff = (csum_offset + 1) * csum_size; | 592 | u32 diff = (csum_offset + 1) * csum_size; |
| 593 | |||
| 594 | /* | ||
| 595 | * is the item big enough already? we dropped our lock | ||
| 596 | * before and need to recheck | ||
| 597 | */ | ||
| 598 | if (diff < btrfs_item_size_nr(leaf, path->slots[0])) | ||
| 599 | goto csum; | ||
| 600 | |||
| 418 | diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); | 601 | diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); |
| 419 | if (diff != csum_size) | 602 | if (diff != csum_size) { |
| 420 | goto insert; | 603 | goto insert; |
| 604 | } | ||
| 605 | |||
| 421 | ret = btrfs_extend_item(trans, root, path, diff); | 606 | ret = btrfs_extend_item(trans, root, path, diff); |
| 422 | BUG_ON(ret); | 607 | BUG_ON(ret); |
| 423 | goto csum; | 608 | goto csum; |
| @@ -518,30 +703,3 @@ out: | |||
| 518 | fail_unlock: | 703 | fail_unlock: |
| 519 | goto out; | 704 | goto out; |
| 520 | } | 705 | } |
| 521 | |||
| 522 | int btrfs_csum_truncate(struct btrfs_trans_handle *trans, | ||
| 523 | struct btrfs_root *root, struct btrfs_path *path, | ||
| 524 | u64 isize) | ||
| 525 | { | ||
| 526 | struct btrfs_key key; | ||
| 527 | struct extent_buffer *leaf = path->nodes[0]; | ||
| 528 | int slot = path->slots[0]; | ||
| 529 | int ret; | ||
| 530 | u32 new_item_size; | ||
| 531 | u64 new_item_span; | ||
| 532 | u64 blocks; | ||
| 533 | |||
| 534 | btrfs_item_key_to_cpu(leaf, &key, slot); | ||
| 535 | if (isize <= key.offset) | ||
| 536 | return 0; | ||
| 537 | new_item_span = isize - key.offset; | ||
| 538 | blocks = (new_item_span + root->sectorsize - 1) >> | ||
| 539 | root->fs_info->sb->s_blocksize_bits; | ||
| 540 | new_item_size = blocks * | ||
| 541 | btrfs_super_csum_size(&root->fs_info->super_copy); | ||
| 542 | if (new_item_size >= btrfs_item_size_nr(leaf, slot)) | ||
| 543 | return 0; | ||
| 544 | ret = btrfs_truncate_item(trans, root, path, new_item_size, 1); | ||
| 545 | BUG_ON(ret); | ||
| 546 | return ret; | ||
| 547 | } | ||
