diff options
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 6b76fd96715..43d4779abdd 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -1249,6 +1249,63 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root return ret; } +int btrfs_truncate_item(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, + u32 new_size) +{ + int ret = 0; + int slot; + int slot_orig; + struct btrfs_leaf *leaf; + struct buffer_head *leaf_buf; + u32 nritems; + unsigned int data_end; + unsigned int old_data_start; + unsigned int old_size; + unsigned int size_diff; + int i; + + slot_orig = path->slots[0]; + leaf_buf = path->nodes[0]; + leaf = btrfs_buffer_leaf(leaf_buf); + + nritems = btrfs_header_nritems(&leaf->header); + data_end = leaf_data_end(root, leaf); + + slot = path->slots[0]; + old_data_start = btrfs_item_offset(leaf->items + slot); + old_size = btrfs_item_size(leaf->items + slot); + BUG_ON(old_size <= new_size); + size_diff = old_size - new_size; + + BUG_ON(slot < 0); + BUG_ON(slot >= nritems); + + /* + * item0..itemN ... dataN.offset..dataN.size .. data0.size + */ + /* first correct the data pointers */ + for (i = slot; i < nritems; i++) { + u32 ioff = btrfs_item_offset(leaf->items + i); + btrfs_set_item_offset(leaf->items + i, + ioff + size_diff); + } + /* shift the data */ +printk("truncate item, new_size %u old_size %u, diff %u, bufp %p, dst, %p, num %u, old_data_start %u, data_end %u\n", new_size, old_size, size_diff, leaf, btrfs_leaf_data(leaf) + data_end + size_diff, old_data_start-data_end, old_data_start, data_end); + btrfs_memmove(root, leaf, btrfs_leaf_data(leaf) + + data_end + size_diff, btrfs_leaf_data(leaf) + + data_end, old_data_start + new_size - data_end); + btrfs_set_item_size(leaf->items + slot, new_size); + btrfs_mark_buffer_dirty(leaf_buf); + + ret = 0; + if (btrfs_leaf_free_space(root, leaf) < 0) + BUG(); + check_leaf(root, path, 0); + return ret; +} + int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u32 data_size) { |