aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.c131
-rw-r--r--fs/btrfs/ctree.h13
-rw-r--r--fs/btrfs/extent-tree.c6
-rw-r--r--fs/btrfs/file-item.c226
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 */
2847int 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
2893split:
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);
1825int 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);
1819int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root 1830int 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 */
1967int btrfs_del_csums(struct btrfs_trans_handle *trans,
1968 struct btrfs_root *root, u64 bytenr, u64 len);
1956int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, 1969int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
1957 struct bio *bio, u32 *dst); 1970 struct bio *bio, u32 *dst);
1958int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, 1971int 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 */
324static 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 */
381int 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 }
481out:
482 btrfs_free_path(path);
483 return 0;
484}
485
313int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, 486int 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:
518fail_unlock: 703fail_unlock:
519 goto out; 704 goto out;
520} 705}
521
522int 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}