aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ctree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-12-10 09:10:46 -0500
committerChris Mason <chris.mason@oracle.com>2008-12-10 09:10:46 -0500
commit459931eca5f4b8c9ad259d07cc1ca49afed54804 (patch)
tree86088c14cff53f93281dc25022b61fb1d86c2458 /fs/btrfs/ctree.c
parent580afd76e451deb6772d0507de580fb1df14da6c (diff)
Btrfs: Delete csum items when freeing extents
This finishes off the new checksumming code by removing csum items for extents that are no longer in use. The trick is doing it without racing because a single csum item may hold csums for more than one extent. Extra checks are added to btrfs_csum_file_blocks to make sure that we are using the correct csum item after dropping locks. A new btrfs_split_item is added to split a single csum item so it can be split without dropping the leaf lock. This is used to remove csum bytes from the middle of an item. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r--fs/btrfs/ctree.c131
1 files changed, 125 insertions, 6 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