Skip to content

Commit

Permalink
Btrfs: update nodatacow code v2
Browse files Browse the repository at this point in the history
This patch simplifies the nodatacow checker. If all references
were created after the latest snapshot, then we can avoid COW
safely. This patch also updates run_delalloc_nocow to do more
fine-grained checking.

Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
  • Loading branch information
Yan Zheng authored and Chris Mason committed Oct 30, 2008
1 parent 6643558 commit 80ff385
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 213 deletions.
8 changes: 5 additions & 3 deletions fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ struct btrfs_root_item {
__le64 bytenr;
__le64 byte_limit;
__le64 bytes_used;
__le64 last_snapshot;
__le32 flags;
__le32 refs;
struct btrfs_disk_key drop_progress;
Expand Down Expand Up @@ -1413,6 +1414,8 @@ BTRFS_SETGET_STACK_FUNCS(root_refs, struct btrfs_root_item, refs, 32);
BTRFS_SETGET_STACK_FUNCS(root_flags, struct btrfs_root_item, flags, 32);
BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64);
BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64);
BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item,
last_snapshot, 64);

/* struct btrfs_super_block */
BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
Expand Down Expand Up @@ -1564,9 +1567,8 @@ int btrfs_update_pinned_extents(struct btrfs_root *root,
u64 bytenr, u64 num, int pin);
int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *leaf);
int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_key *key, u64 bytenr);
int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr);
int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy);
Expand Down
131 changes: 18 additions & 113 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -848,18 +848,17 @@ int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans,
return 0;
}

static int get_reference_status(struct btrfs_root *root, u64 bytenr,
u64 parent_gen, u64 ref_objectid,
u64 *min_generation, u32 *ref_count)
int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytenr)
{
struct btrfs_root *extent_root = root->fs_info->extent_root;
struct btrfs_path *path;
struct extent_buffer *leaf;
struct btrfs_extent_ref *ref_item;
struct btrfs_key key;
struct btrfs_key found_key;
u64 root_objectid = root->root_key.objectid;
u64 ref_generation;
u64 ref_root;
u64 last_snapshot;
u32 nritems;
int ret;

Expand All @@ -872,22 +871,20 @@ static int get_reference_status(struct btrfs_root *root, u64 bytenr,
if (ret < 0)
goto out;
BUG_ON(ret == 0);
if (ret < 0 || path->slots[0] == 0)

ret = -ENOENT;
if (path->slots[0] == 0)
goto out;

path->slots[0]--;
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);

if (found_key.objectid != bytenr ||
found_key.type != BTRFS_EXTENT_ITEM_KEY) {
ret = 1;
found_key.type != BTRFS_EXTENT_ITEM_KEY)
goto out;
}

*ref_count = 0;
*min_generation = (u64)-1;

last_snapshot = btrfs_root_last_snapshot(&root->root_item);
while (1) {
leaf = path->nodes[0];
nritems = btrfs_header_nritems(leaf);
Expand All @@ -910,114 +907,22 @@ static int get_reference_status(struct btrfs_root *root, u64 bytenr,

ref_item = btrfs_item_ptr(leaf, path->slots[0],
struct btrfs_extent_ref);
ref_generation = btrfs_ref_generation(leaf, ref_item);
/*
* For (parent_gen > 0 && parent_gen > ref_generation):
*
* we reach here through the oldest root, therefore
* all other reference from same snapshot should have
* a larger generation.
*/
if ((root_objectid != btrfs_ref_root(leaf, ref_item)) ||
(parent_gen > 0 && parent_gen > ref_generation) ||
(ref_objectid >= BTRFS_FIRST_FREE_OBJECTID &&
ref_objectid != btrfs_ref_objectid(leaf, ref_item))) {
*ref_count = 2;
break;
}

*ref_count = 1;
if (*min_generation > ref_generation)
*min_generation = ref_generation;

path->slots[0]++;
}
ret = 0;
out:
btrfs_free_path(path);
return ret;
}

int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_key *key, u64 bytenr)
{
struct btrfs_root *old_root;
struct btrfs_path *path = NULL;
struct extent_buffer *eb;
struct btrfs_file_extent_item *item;
u64 ref_generation;
u64 min_generation;
u64 extent_start;
u32 ref_count;
int level;
int ret;

BUG_ON(trans == NULL);
BUG_ON(key->type != BTRFS_EXTENT_DATA_KEY);
ret = get_reference_status(root, bytenr, 0, key->objectid,
&min_generation, &ref_count);
if (ret)
return ret;

if (ref_count != 1)
return 1;

old_root = root->dirty_root->root;
ref_generation = old_root->root_key.offset;

/* all references are created in running transaction */
if (min_generation > ref_generation) {
ret = 0;
goto out;
}

path = btrfs_alloc_path();
if (!path) {
ret = -ENOMEM;
goto out;
}

path->skip_locking = 1;
/* if no item found, the extent is referenced by other snapshot */
ret = btrfs_search_slot(NULL, old_root, key, path, 0, 0);
if (ret)
goto out;

eb = path->nodes[0];
item = btrfs_item_ptr(eb, path->slots[0],
struct btrfs_file_extent_item);
if (btrfs_file_extent_type(eb, item) != BTRFS_FILE_EXTENT_REG ||
btrfs_file_extent_disk_bytenr(eb, item) != bytenr) {
ret = 1;
goto out;
}

for (level = BTRFS_MAX_LEVEL - 1; level >= -1; level--) {
if (level >= 0) {
eb = path->nodes[level];
if (!eb)
continue;
extent_start = eb->start;
} else
extent_start = bytenr;

ret = get_reference_status(root, extent_start, ref_generation,
0, &min_generation, &ref_count);
if (ret)
ref_root = btrfs_ref_root(leaf, ref_item);
if (ref_root != root->root_key.objectid &&
ref_root != BTRFS_TREE_LOG_OBJECTID) {
ret = 1;
goto out;

if (ref_count != 1) {
}
if (btrfs_ref_generation(leaf, ref_item) <= last_snapshot) {
ret = 1;
goto out;
}
if (level >= 0)
ref_generation = btrfs_header_generation(eb);

path->slots[0]++;
}
ret = 0;
out:
if (path)
btrfs_free_path(path);
btrfs_free_path(path);
return ret;
}

Expand Down
Loading

0 comments on commit 80ff385

Please sign in to comment.