Skip to content

Commit

Permalink
Btrfs: Delete csum items when freeing extents
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Chris Mason committed Dec 10, 2008
1 parent 580afd7 commit 459931e
Show file tree
Hide file tree
Showing 4 changed files with 335 additions and 41 deletions.
131 changes: 125 additions & 6 deletions fs/btrfs/ctree.c
Original file line number Diff line number Diff line change
Expand Up @@ -1512,7 +1512,8 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
if (ret && slot > 0)
slot -= 1;
p->slots[level] = slot;
if (ins_len > 0 && btrfs_header_nritems(b) >=
if ((p->search_for_split || ins_len > 0) &&
btrfs_header_nritems(b) >=
BTRFS_NODEPTRS_PER_BLOCK(root) - 3) {
int sret = split_node(trans, root, p, level);
BUG_ON(sret > 0);
Expand Down Expand Up @@ -1596,7 +1597,8 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
goto done;
}
}
unlock_up(p, level, lowest_unlock);
if (!p->search_for_split)
unlock_up(p, level, lowest_unlock);
goto done;
}
}
Expand Down Expand Up @@ -2636,11 +2638,11 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
int num_doubles = 0;
struct btrfs_disk_key disk_key;

if (extend)
if (extend && data_size)
space_needed = data_size;

/* first try to make some room by pushing left and right */
if (ins_key->type != BTRFS_DIR_ITEM_KEY) {
if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) {
wret = push_leaf_right(trans, root, path, data_size, 0);
if (wret < 0) {
return wret;
Expand Down Expand Up @@ -2721,7 +2723,7 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
} else {
if (leaf_space_used(l, 0, mid + 1) + space_needed >
BTRFS_LEAF_DATA_SIZE(root)) {
if (!extend && slot == 0) {
if (!extend && data_size && slot == 0) {
btrfs_cpu_key_to_disk(&disk_key, ins_key);
btrfs_set_header_nritems(right, 0);
wret = insert_ptr(trans, root, path,
Expand All @@ -2742,7 +2744,7 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
}
btrfs_mark_buffer_dirty(right);
return ret;
} else if (extend && slot == 0) {
} else if ((extend || !data_size) && slot == 0) {
mid = 1;
} else {
mid = slot;
Expand Down Expand Up @@ -2827,6 +2829,123 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
return ret;
}

/*
* This function splits a single item into two items,
* giving 'new_key' to the new item and splitting the
* old one at split_offset (from the start of the item).
*
* The path may be released by this operation. After
* the split, the path is pointing to the old item. The
* new item is going to be in the same node as the old one.
*
* Note, the item being split must be smaller enough to live alone on
* a tree block with room for one extra struct btrfs_item
*
* This allows us to split the item in place, keeping a lock on the
* leaf the entire time.
*/
int btrfs_split_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
struct btrfs_key *new_key,
unsigned long split_offset)
{
u32 item_size;
struct extent_buffer *leaf;
struct btrfs_key orig_key;
struct btrfs_item *item;
struct btrfs_item *new_item;
int ret = 0;
int slot;
u32 nritems;
u32 orig_offset;
struct btrfs_disk_key disk_key;
char *buf;

leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &orig_key, path->slots[0]);
if (btrfs_leaf_free_space(root, leaf) >= sizeof(struct btrfs_item))
goto split;

item_size = btrfs_item_size_nr(leaf, path->slots[0]);
btrfs_release_path(root, path);

path->search_for_split = 1;
path->keep_locks = 1;

ret = btrfs_search_slot(trans, root, &orig_key, path, 0, 1);
path->search_for_split = 0;

/* if our item isn't there or got smaller, return now */
if (ret != 0 || item_size != btrfs_item_size_nr(path->nodes[0],
path->slots[0])) {
path->keep_locks = 0;
return -EAGAIN;
}

ret = split_leaf(trans, root, &orig_key, path, 0, 0);
path->keep_locks = 0;
BUG_ON(ret);

BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item));
leaf = path->nodes[0];

split:
item = btrfs_item_nr(leaf, path->slots[0]);
orig_offset = btrfs_item_offset(leaf, item);
item_size = btrfs_item_size(leaf, item);


buf = kmalloc(item_size, GFP_NOFS);
read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf,
path->slots[0]), item_size);
slot = path->slots[0] + 1;
leaf = path->nodes[0];

nritems = btrfs_header_nritems(leaf);

if (slot != nritems) {
/* shift the items */
memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1),
btrfs_item_nr_offset(slot),
(nritems - slot) * sizeof(struct btrfs_item));

}

btrfs_cpu_key_to_disk(&disk_key, new_key);
btrfs_set_item_key(leaf, &disk_key, slot);

new_item = btrfs_item_nr(leaf, slot);

btrfs_set_item_offset(leaf, new_item, orig_offset);
btrfs_set_item_size(leaf, new_item, item_size - split_offset);

btrfs_set_item_offset(leaf, item,
orig_offset + item_size - split_offset);
btrfs_set_item_size(leaf, item, split_offset);

btrfs_set_header_nritems(leaf, nritems + 1);

/* write the data for the start of the original item */
write_extent_buffer(leaf, buf,
btrfs_item_ptr_offset(leaf, path->slots[0]),
split_offset);

/* write the data for the new item */
write_extent_buffer(leaf, buf + split_offset,
btrfs_item_ptr_offset(leaf, slot),
item_size - split_offset);
btrfs_mark_buffer_dirty(leaf);

ret = 0;
if (btrfs_leaf_free_space(root, leaf) < 0) {
btrfs_print_leaf(root, leaf);
BUG();
}
kfree(buf);
return ret;
}

/*
* make the item pointed to by the path smaller. new_size indicates
* how small to make it, and from_end tells us if we just chop bytes
Expand Down
13 changes: 13 additions & 0 deletions fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,12 @@ struct btrfs_path {
int keep_locks;
int skip_locking;
int lowest_level;

/*
* set by btrfs_split_item, tells search_slot to keep all locks
* and to force calls to keep space in the nodes
*/
int search_for_split;
};

/*
Expand Down Expand Up @@ -1816,6 +1822,11 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
u32 new_size, int from_end);
int btrfs_split_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
struct btrfs_key *new_key,
unsigned long split_offset);
int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
*root, struct btrfs_key *key, struct btrfs_path *p, int
ins_len, int cow);
Expand Down Expand Up @@ -1953,6 +1964,8 @@ int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
struct btrfs_key *location, int mod);

/* file-item.c */
int btrfs_del_csums(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr, u64 len);
int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
struct bio *bio, u32 *dst);
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
Expand Down
6 changes: 5 additions & 1 deletion fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -2484,7 +2484,6 @@ static int __free_extent(struct btrfs_trans_handle *trans,
mark_free = 1;
BUG_ON(ret < 0);
}

/* block accounting for super block */
spin_lock_irq(&info->delalloc_lock);
super_used = btrfs_super_bytes_used(&info->super_copy);
Expand All @@ -2504,6 +2503,11 @@ static int __free_extent(struct btrfs_trans_handle *trans,
mark_free);
BUG_ON(ret);

if (owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) {
ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
BUG_ON(ret);
}

#ifdef BIO_RW_DISCARD
/* Tell the block device(s) that the sectors can be discarded */
ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
Expand Down
Loading

0 comments on commit 459931e

Please sign in to comment.