Btrfs: progress on file_write
[linux-2.6-block.git] / fs / btrfs / ctree.c
index 6b76fd967153b87f886e66d0db5f51662e90eb5e..43d4779abdd1c28d4d4e79c5ef812678c96c2976 100644 (file)
@@ -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)
 {