diff options
-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 19c0dd33b1e8..c0c95cccbb5b 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 f72b43819349..5b0c79d22c09 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 803647bc8400..cc74316dc426 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 a3ad2ce00116..3ebef871ee6c 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 | } | ||