summaryrefslogtreecommitdiff
path: root/fs/btrfs/delayed-ref.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/delayed-ref.c')
-rw-r--r--fs/btrfs/delayed-ref.c509
1 files changed, 380 insertions, 129 deletions
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c
index d6c01c096a40..84e6781413b1 100644
--- a/fs/btrfs/delayed-ref.c
+++ b/fs/btrfs/delayed-ref.c
@@ -29,27 +29,87 @@
* add extents in the middle of btrfs_search_slot, and it allows
* us to buffer up frequently modified backrefs in an rb tree instead
* of hammering updates on the extent allocation tree.
- *
- * Right now this code is only used for reference counted trees, but
- * the long term goal is to get rid of the similar code for delayed
- * extent tree modifications.
*/
/*
- * entries in the rb tree are ordered by the byte number of the extent
- * and by the byte number of the parent block.
+ * compare two delayed tree backrefs with same bytenr and type
+ */
+static int comp_tree_refs(struct btrfs_delayed_tree_ref *ref2,
+ struct btrfs_delayed_tree_ref *ref1)
+{
+ if (ref1->node.type == BTRFS_TREE_BLOCK_REF_KEY) {
+ if (ref1->root < ref2->root)
+ return -1;
+ if (ref1->root > ref2->root)
+ return 1;
+ } else {
+ if (ref1->parent < ref2->parent)
+ return -1;
+ if (ref1->parent > ref2->parent)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * compare two delayed data backrefs with same bytenr and type
*/
-static int comp_entry(struct btrfs_delayed_ref_node *ref,
- u64 bytenr, u64 parent)
+static int comp_data_refs(struct btrfs_delayed_data_ref *ref2,
+ struct btrfs_delayed_data_ref *ref1)
{
- if (bytenr < ref->bytenr)
+ if (ref1->node.type == BTRFS_EXTENT_DATA_REF_KEY) {
+ if (ref1->root < ref2->root)
+ return -1;
+ if (ref1->root > ref2->root)
+ return 1;
+ if (ref1->objectid < ref2->objectid)
+ return -1;
+ if (ref1->objectid > ref2->objectid)
+ return 1;
+ if (ref1->offset < ref2->offset)
+ return -1;
+ if (ref1->offset > ref2->offset)
+ return 1;
+ } else {
+ if (ref1->parent < ref2->parent)
+ return -1;
+ if (ref1->parent > ref2->parent)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * entries in the rb tree are ordered by the byte number of the extent,
+ * type of the delayed backrefs and content of delayed backrefs.
+ */
+static int comp_entry(struct btrfs_delayed_ref_node *ref2,
+ struct btrfs_delayed_ref_node *ref1)
+{
+ if (ref1->bytenr < ref2->bytenr)
return -1;
- if (bytenr > ref->bytenr)
+ if (ref1->bytenr > ref2->bytenr)
return 1;
- if (parent < ref->parent)
+ if (ref1->is_head && ref2->is_head)
+ return 0;
+ if (ref2->is_head)
return -1;
- if (parent > ref->parent)
+ if (ref1->is_head)
return 1;
+ if (ref1->type < ref2->type)
+ return -1;
+ if (ref1->type > ref2->type)
+ return 1;
+ if (ref1->type == BTRFS_TREE_BLOCK_REF_KEY ||
+ ref1->type == BTRFS_SHARED_BLOCK_REF_KEY) {
+ return comp_tree_refs(btrfs_delayed_node_to_tree_ref(ref2),
+ btrfs_delayed_node_to_tree_ref(ref1));
+ } else if (ref1->type == BTRFS_EXTENT_DATA_REF_KEY ||
+ ref1->type == BTRFS_SHARED_DATA_REF_KEY) {
+ return comp_data_refs(btrfs_delayed_node_to_data_ref(ref2),
+ btrfs_delayed_node_to_data_ref(ref1));
+ }
+ BUG();
return 0;
}
@@ -59,20 +119,21 @@ static int comp_entry(struct btrfs_delayed_ref_node *ref,
* inserted.
*/
static struct btrfs_delayed_ref_node *tree_insert(struct rb_root *root,
- u64 bytenr, u64 parent,
struct rb_node *node)
{
struct rb_node **p = &root->rb_node;
struct rb_node *parent_node = NULL;
struct btrfs_delayed_ref_node *entry;
+ struct btrfs_delayed_ref_node *ins;
int cmp;
+ ins = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
while (*p) {
parent_node = *p;
entry = rb_entry(parent_node, struct btrfs_delayed_ref_node,
rb_node);
- cmp = comp_entry(entry, bytenr, parent);
+ cmp = comp_entry(entry, ins);
if (cmp < 0)
p = &(*p)->rb_left;
else if (cmp > 0)
@@ -81,18 +142,17 @@ static struct btrfs_delayed_ref_node *tree_insert(struct rb_root *root,
return entry;
}
- entry = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
rb_link_node(node, parent_node, p);
rb_insert_color(node, root);
return NULL;
}
/*
- * find an entry based on (bytenr,parent). This returns the delayed
- * ref if it was able to find one, or NULL if nothing was in that spot
+ * find an head entry based on bytenr. This returns the delayed ref
+ * head if it was able to find one, or NULL if nothing was in that spot
*/
-static struct btrfs_delayed_ref_node *tree_search(struct rb_root *root,
- u64 bytenr, u64 parent,
+static struct btrfs_delayed_ref_node *find_ref_head(struct rb_root *root,
+ u64 bytenr,
struct btrfs_delayed_ref_node **last)
{
struct rb_node *n = root->rb_node;
@@ -105,7 +165,15 @@ static struct btrfs_delayed_ref_node *tree_search(struct rb_root *root,
if (last)
*last = entry;
- cmp = comp_entry(entry, bytenr, parent);
+ if (bytenr < entry->bytenr)
+ cmp = -1;
+ else if (bytenr > entry->bytenr)
+ cmp = 1;
+ else if (!btrfs_delayed_ref_is_head(entry))
+ cmp = 1;
+ else
+ cmp = 0;
+
if (cmp < 0)
n = n->rb_left;
else if (cmp > 0)
@@ -154,7 +222,7 @@ int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
node = rb_first(&delayed_refs->root);
} else {
ref = NULL;
- tree_search(&delayed_refs->root, start, (u64)-1, &ref);
+ find_ref_head(&delayed_refs->root, start, &ref);
if (ref) {
struct btrfs_delayed_ref_node *tmp;
@@ -234,7 +302,7 @@ int btrfs_delayed_ref_pending(struct btrfs_trans_handle *trans, u64 bytenr)
delayed_refs = &trans->transaction->delayed_refs;
spin_lock(&delayed_refs->lock);
- ref = tree_search(&delayed_refs->root, bytenr, (u64)-1, NULL);
+ ref = find_ref_head(&delayed_refs->root, bytenr, NULL);
if (ref) {
prev_node = rb_prev(&ref->rb_node);
if (!prev_node)
@@ -250,25 +318,28 @@ out:
}
/*
- * helper function to lookup reference count
+ * helper function to lookup reference count and flags of extent.
*
* the head node for delayed ref is used to store the sum of all the
- * reference count modifications queued up in the rbtree. This way you
- * can check to see what the reference count would be if all of the
- * delayed refs are processed.
+ * reference count modifications queued up in the rbtree. the head
+ * node may also store the extent flags to set. This way you can check
+ * to see what the reference count and extent flags would be if all of
+ * the delayed refs are not processed.
*/
-int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans,
- struct btrfs_root *root, u64 bytenr,
- u64 num_bytes, u32 *refs)
+int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 bytenr,
+ u64 num_bytes, u64 *refs, u64 *flags)
{
struct btrfs_delayed_ref_node *ref;
struct btrfs_delayed_ref_head *head;
struct btrfs_delayed_ref_root *delayed_refs;
struct btrfs_path *path;
- struct extent_buffer *leaf;
struct btrfs_extent_item *ei;
+ struct extent_buffer *leaf;
struct btrfs_key key;
- u32 num_refs;
+ u32 item_size;
+ u64 num_refs;
+ u64 extent_flags;
int ret;
path = btrfs_alloc_path();
@@ -287,37 +358,60 @@ again:
if (ret == 0) {
leaf = path->nodes[0];
- ei = btrfs_item_ptr(leaf, path->slots[0],
- struct btrfs_extent_item);
- num_refs = btrfs_extent_refs(leaf, ei);
+ item_size = btrfs_item_size_nr(leaf, path->slots[0]);
+ if (item_size >= sizeof(*ei)) {
+ ei = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_extent_item);
+ num_refs = btrfs_extent_refs(leaf, ei);
+ extent_flags = btrfs_extent_flags(leaf, ei);
+ } else {
+#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
+ struct btrfs_extent_item_v0 *ei0;
+ BUG_ON(item_size != sizeof(*ei0));
+ ei0 = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_extent_item_v0);
+ num_refs = btrfs_extent_refs_v0(leaf, ei0);
+ /* FIXME: this isn't correct for data */
+ extent_flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
+#else
+ BUG();
+#endif
+ }
+ BUG_ON(num_refs == 0);
} else {
num_refs = 0;
+ extent_flags = 0;
ret = 0;
}
spin_lock(&delayed_refs->lock);
- ref = tree_search(&delayed_refs->root, bytenr, (u64)-1, NULL);
+ ref = find_ref_head(&delayed_refs->root, bytenr, NULL);
if (ref) {
head = btrfs_delayed_node_to_head(ref);
- if (mutex_trylock(&head->mutex)) {
- num_refs += ref->ref_mod;
- mutex_unlock(&head->mutex);
- *refs = num_refs;
- goto out;
- }
+ if (!mutex_trylock(&head->mutex)) {
+ atomic_inc(&ref->refs);
+ spin_unlock(&delayed_refs->lock);
- atomic_inc(&ref->refs);
- spin_unlock(&delayed_refs->lock);
+ btrfs_release_path(root->fs_info->extent_root, path);
- btrfs_release_path(root->fs_info->extent_root, path);
+ mutex_lock(&head->mutex);
+ mutex_unlock(&head->mutex);
+ btrfs_put_delayed_ref(ref);
+ goto again;
+ }
+ if (head->extent_op && head->extent_op->update_flags)
+ extent_flags |= head->extent_op->flags_to_set;
+ else
+ BUG_ON(num_refs == 0);
- mutex_lock(&head->mutex);
+ num_refs += ref->ref_mod;
mutex_unlock(&head->mutex);
- btrfs_put_delayed_ref(ref);
- goto again;
- } else {
- *refs = num_refs;
}
+ WARN_ON(num_refs == 0);
+ if (refs)
+ *refs = num_refs;
+ if (flags)
+ *flags = extent_flags;
out:
spin_unlock(&delayed_refs->lock);
btrfs_free_path(path);
@@ -338,16 +432,7 @@ update_existing_ref(struct btrfs_trans_handle *trans,
struct btrfs_delayed_ref_node *existing,
struct btrfs_delayed_ref_node *update)
{
- struct btrfs_delayed_ref *existing_ref;
- struct btrfs_delayed_ref *ref;
-
- existing_ref = btrfs_delayed_node_to_ref(existing);
- ref = btrfs_delayed_node_to_ref(update);
-
- if (ref->pin)
- existing_ref->pin = 1;
-
- if (ref->action != existing_ref->action) {
+ if (update->action != existing->action) {
/*
* this is effectively undoing either an add or a
* drop. We decrement the ref_mod, and if it goes
@@ -363,20 +448,13 @@ update_existing_ref(struct btrfs_trans_handle *trans,
delayed_refs->num_entries--;
if (trans->delayed_ref_updates)
trans->delayed_ref_updates--;
+ } else {
+ WARN_ON(existing->type == BTRFS_TREE_BLOCK_REF_KEY ||
+ existing->type == BTRFS_SHARED_BLOCK_REF_KEY);
}
} else {
- if (existing_ref->action == BTRFS_ADD_DELAYED_REF) {
- /* if we're adding refs, make sure all the
- * details match up. The extent could
- * have been totally freed and reallocated
- * by a different owner before the delayed
- * ref entries were removed.
- */
- existing_ref->owner_objectid = ref->owner_objectid;
- existing_ref->generation = ref->generation;
- existing_ref->root = ref->root;
- existing->num_bytes = update->num_bytes;
- }
+ WARN_ON(existing->type == BTRFS_TREE_BLOCK_REF_KEY ||
+ existing->type == BTRFS_SHARED_BLOCK_REF_KEY);
/*
* the action on the existing ref matches
* the action on the ref we're trying to add.
@@ -401,6 +479,7 @@ update_existing_head_ref(struct btrfs_delayed_ref_node *existing,
existing_ref = btrfs_delayed_node_to_head(existing);
ref = btrfs_delayed_node_to_head(update);
+ BUG_ON(existing_ref->is_data != ref->is_data);
if (ref->must_insert_reserved) {
/* if the extent was freed and then
@@ -420,6 +499,24 @@ update_existing_head_ref(struct btrfs_delayed_ref_node *existing,
}
+ if (ref->extent_op) {
+ if (!existing_ref->extent_op) {
+ existing_ref->extent_op = ref->extent_op;
+ } else {
+ if (ref->extent_op->update_key) {
+ memcpy(&existing_ref->extent_op->key,
+ &ref->extent_op->key,
+ sizeof(ref->extent_op->key));
+ existing_ref->extent_op->update_key = 1;
+ }
+ if (ref->extent_op->update_flags) {
+ existing_ref->extent_op->flags_to_set |=
+ ref->extent_op->flags_to_set;
+ existing_ref->extent_op->update_flags = 1;
+ }
+ kfree(ref->extent_op);
+ }
+ }
/*
* update the reference mod on the head to reflect this new operation
*/
@@ -427,19 +524,16 @@ update_existing_head_ref(struct btrfs_delayed_ref_node *existing,
}
/*
- * helper function to actually insert a delayed ref into the rbtree.
+ * helper function to actually insert a head node into the rbtree.
* this does all the dirty work in terms of maintaining the correct
- * overall modification count in the head node and properly dealing
- * with updating existing nodes as new modifications are queued.
+ * overall modification count.
*/
-static noinline int __btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
- struct btrfs_delayed_ref_node *ref,
- u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root,
- u64 ref_generation, u64 owner_objectid, int action,
- int pin)
+static noinline int add_delayed_ref_head(struct btrfs_trans_handle *trans,
+ struct btrfs_delayed_ref_node *ref,
+ u64 bytenr, u64 num_bytes,
+ int action, int is_data)
{
struct btrfs_delayed_ref_node *existing;
- struct btrfs_delayed_ref *full_ref;
struct btrfs_delayed_ref_head *head_ref = NULL;
struct btrfs_delayed_ref_root *delayed_refs;
int count_mod = 1;
@@ -449,12 +543,10 @@ static noinline int __btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
* the head node stores the sum of all the mods, so dropping a ref
* should drop the sum in the head node by one.
*/
- if (parent == (u64)-1) {
- if (action == BTRFS_DROP_DELAYED_REF)
- count_mod = -1;
- else if (action == BTRFS_UPDATE_DELAYED_HEAD)
- count_mod = 0;
- }
+ if (action == BTRFS_UPDATE_DELAYED_HEAD)
+ count_mod = 0;
+ else if (action == BTRFS_DROP_DELAYED_REF)
+ count_mod = -1;
/*
* BTRFS_ADD_DELAYED_EXTENT means that we need to update
@@ -467,57 +559,148 @@ static noinline int __btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
* Once we record must_insert_reserved, switch the action to
* BTRFS_ADD_DELAYED_REF because other special casing is not required.
*/
- if (action == BTRFS_ADD_DELAYED_EXTENT) {
+ if (action == BTRFS_ADD_DELAYED_EXTENT)
must_insert_reserved = 1;
- action = BTRFS_ADD_DELAYED_REF;
- } else {
+ else
must_insert_reserved = 0;
- }
-
delayed_refs = &trans->transaction->delayed_refs;
/* first set the basic ref node struct up */
atomic_set(&ref->refs, 1);
ref->bytenr = bytenr;
- ref->parent = parent;
+ ref->num_bytes = num_bytes;
ref->ref_mod = count_mod;
+ ref->type = 0;
+ ref->action = 0;
+ ref->is_head = 1;
ref->in_tree = 1;
+
+ head_ref = btrfs_delayed_node_to_head(ref);
+ head_ref->must_insert_reserved = must_insert_reserved;
+ head_ref->is_data = is_data;
+
+ INIT_LIST_HEAD(&head_ref->cluster);
+ mutex_init(&head_ref->mutex);
+
+ existing = tree_insert(&delayed_refs->root, &ref->rb_node);
+
+ if (existing) {
+ update_existing_head_ref(existing, ref);
+ /*
+ * we've updated the existing ref, free the newly
+ * allocated ref
+ */
+ kfree(ref);
+ } else {
+ delayed_refs->num_heads++;
+ delayed_refs->num_heads_ready++;
+ delayed_refs->num_entries++;
+ trans->delayed_ref_updates++;
+ }
+ return 0;
+}
+
+/*
+ * helper to insert a delayed tree ref into the rbtree.
+ */
+static noinline int add_delayed_tree_ref(struct btrfs_trans_handle *trans,
+ struct btrfs_delayed_ref_node *ref,
+ u64 bytenr, u64 num_bytes, u64 parent,
+ u64 ref_root, int level, int action)
+{
+ struct btrfs_delayed_ref_node *existing;
+ struct btrfs_delayed_tree_ref *full_ref;
+ struct btrfs_delayed_ref_root *delayed_refs;
+
+ if (action == BTRFS_ADD_DELAYED_EXTENT)
+ action = BTRFS_ADD_DELAYED_REF;
+
+ delayed_refs = &trans->transaction->delayed_refs;
+
+ /* first set the basic ref node struct up */
+ atomic_set(&ref->refs, 1);
+ ref->bytenr = bytenr;
ref->num_bytes = num_bytes;
+ ref->ref_mod = 1;
+ ref->action = action;
+ ref->is_head = 0;
+ ref->in_tree = 1;
- if (btrfs_delayed_ref_is_head(ref)) {
- head_ref = btrfs_delayed_node_to_head(ref);
- head_ref->must_insert_reserved = must_insert_reserved;
- INIT_LIST_HEAD(&head_ref->cluster);
- mutex_init(&head_ref->mutex);
+ full_ref = btrfs_delayed_node_to_tree_ref(ref);
+ if (parent) {
+ full_ref->parent = parent;
+ ref->type = BTRFS_SHARED_BLOCK_REF_KEY;
} else {
- full_ref = btrfs_delayed_node_to_ref(ref);
full_ref->root = ref_root;
- full_ref->generation = ref_generation;
- full_ref->owner_objectid = owner_objectid;
- full_ref->pin = pin;
- full_ref->action = action;
+ ref->type = BTRFS_TREE_BLOCK_REF_KEY;
}
+ full_ref->level = level;
- existing = tree_insert(&delayed_refs->root, bytenr,
- parent, &ref->rb_node);
+ existing = tree_insert(&delayed_refs->root, &ref->rb_node);
if (existing) {
- if (btrfs_delayed_ref_is_head(ref))
- update_existing_head_ref(existing, ref);
- else
- update_existing_ref(trans, delayed_refs, existing, ref);
+ update_existing_ref(trans, delayed_refs, existing, ref);
+ /*
+ * we've updated the existing ref, free the newly
+ * allocated ref
+ */
+ kfree(ref);
+ } else {
+ delayed_refs->num_entries++;
+ trans->delayed_ref_updates++;
+ }
+ return 0;
+}
+
+/*
+ * helper to insert a delayed data ref into the rbtree.
+ */
+static noinline int add_delayed_data_ref(struct btrfs_trans_handle *trans,
+ struct btrfs_delayed_ref_node *ref,
+ u64 bytenr, u64 num_bytes, u64 parent,
+ u64 ref_root, u64 owner, u64 offset,
+ int action)
+{
+ struct btrfs_delayed_ref_node *existing;
+ struct btrfs_delayed_data_ref *full_ref;
+ struct btrfs_delayed_ref_root *delayed_refs;
+
+ if (action == BTRFS_ADD_DELAYED_EXTENT)
+ action = BTRFS_ADD_DELAYED_REF;
+
+ delayed_refs = &trans->transaction->delayed_refs;
+
+ /* first set the basic ref node struct up */
+ atomic_set(&ref->refs, 1);
+ ref->bytenr = bytenr;
+ ref->num_bytes = num_bytes;
+ ref->ref_mod = 1;
+ ref->action = action;
+ ref->is_head = 0;
+ ref->in_tree = 1;
+
+ full_ref = btrfs_delayed_node_to_data_ref(ref);
+ if (parent) {
+ full_ref->parent = parent;
+ ref->type = BTRFS_SHARED_DATA_REF_KEY;
+ } else {
+ full_ref->root = ref_root;
+ ref->type = BTRFS_EXTENT_DATA_REF_KEY;
+ }
+ full_ref->objectid = owner;
+ full_ref->offset = offset;
+ existing = tree_insert(&delayed_refs->root, &ref->rb_node);
+
+ if (existing) {
+ update_existing_ref(trans, delayed_refs, existing, ref);
/*
* we've updated the existing ref, free the newly
* allocated ref
*/
kfree(ref);
} else {
- if (btrfs_delayed_ref_is_head(ref)) {
- delayed_refs->num_heads++;
- delayed_refs->num_heads_ready++;
- }
delayed_refs->num_entries++;
trans->delayed_ref_updates++;
}
@@ -525,37 +708,78 @@ static noinline int __btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
}
/*
- * add a delayed ref to the tree. This does all of the accounting required
+ * add a delayed tree ref. This does all of the accounting required
* to make sure the delayed ref is eventually processed before this
* transaction commits.
*/
-int btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
- u64 bytenr, u64 num_bytes, u64 parent, u64 ref_root,
- u64 ref_generation, u64 owner_objectid, int action,
- int pin)
+int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans,
+ u64 bytenr, u64 num_bytes, u64 parent,
+ u64 ref_root, int level, int action,
+ struct btrfs_delayed_extent_op *extent_op)
{
- struct btrfs_delayed_ref *ref;
+ struct btrfs_delayed_tree_ref *ref;
struct btrfs_delayed_ref_head *head_ref;
struct btrfs_delayed_ref_root *delayed_refs;
int ret;
+ BUG_ON(extent_op && extent_op->is_data);
ref = kmalloc(sizeof(*ref), GFP_NOFS);
if (!ref)
return -ENOMEM;
+ head_ref = kmalloc(sizeof(*head_ref), GFP_NOFS);
+ if (!head_ref) {
+ kfree(ref);
+ return -ENOMEM;
+ }
+
+ head_ref->extent_op = extent_op;
+
+ delayed_refs = &trans->transaction->delayed_refs;
+ spin_lock(&delayed_refs->lock);
+
/*
- * the parent = 0 case comes from cases where we don't actually
- * know the parent yet. It will get updated later via a add/drop
- * pair.
+ * insert both the head node and the new ref without dropping
+ * the spin lock
*/
- if (parent == 0)
- parent = bytenr;
+ ret = add_delayed_ref_head(trans, &head_ref->node, bytenr, num_bytes,
+ action, 0);
+ BUG_ON(ret);
+
+ ret = add_delayed_tree_ref(trans, &ref->node, bytenr, num_bytes,
+ parent, ref_root, level, action);
+ BUG_ON(ret);
+ spin_unlock(&delayed_refs->lock);
+ return 0;
+}
+
+/*
+ * add a delayed data ref. it's similar to btrfs_add_delayed_tree_ref.
+ */
+int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans,
+ u64 bytenr, u64 num_bytes,
+ u64 parent, u64 ref_root,
+ u64 owner, u64 offset, int action,
+ struct btrfs_delayed_extent_op *extent_op)
+{
+ struct btrfs_delayed_data_ref *ref;
+ struct btrfs_delayed_ref_head *head_ref;
+ struct btrfs_delayed_ref_root *delayed_refs;
+ int ret;
+
+ BUG_ON(extent_op && !extent_op->is_data);
+ ref = kmalloc(sizeof(*ref), GFP_NOFS);
+ if (!ref)
+ return -ENOMEM;
head_ref = kmalloc(sizeof(*head_ref), GFP_NOFS);
if (!head_ref) {
kfree(ref);
return -ENOMEM;
}
+
+ head_ref->extent_op = extent_op;
+
delayed_refs = &trans->transaction->delayed_refs;
spin_lock(&delayed_refs->lock);
@@ -563,14 +787,39 @@ int btrfs_add_delayed_ref(struct btrfs_trans_handle *trans,
* insert both the head node and the new ref without dropping
* the spin lock
*/
- ret = __btrfs_add_delayed_ref(trans, &head_ref->node, bytenr, num_bytes,
- (u64)-1, 0, 0, 0, action, pin);
+ ret = add_delayed_ref_head(trans, &head_ref->node, bytenr, num_bytes,
+ action, 1);
BUG_ON(ret);
- ret = __btrfs_add_delayed_ref(trans, &ref->node, bytenr, num_bytes,
- parent, ref_root, ref_generation,
- owner_objectid, action, pin);
+ ret = add_delayed_data_ref(trans, &ref->node, bytenr, num_bytes,
+ parent, ref_root, owner, offset, action);
+ BUG_ON(ret);
+ spin_unlock(&delayed_refs->lock);
+ return 0;
+}
+
+int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans,
+ u64 bytenr, u64 num_bytes,
+ struct btrfs_delayed_extent_op *extent_op)
+{
+ struct btrfs_delayed_ref_head *head_ref;
+ struct btrfs_delayed_ref_root *delayed_refs;
+ int ret;
+
+ head_ref = kmalloc(sizeof(*head_ref), GFP_NOFS);
+ if (!head_ref)
+ return -ENOMEM;
+
+ head_ref->extent_op = extent_op;
+
+ delayed_refs = &trans->transaction->delayed_refs;
+ spin_lock(&delayed_refs->lock);
+
+ ret = add_delayed_ref_head(trans, &head_ref->node, bytenr,
+ num_bytes, BTRFS_UPDATE_DELAYED_HEAD,
+ extent_op->is_data);
BUG_ON(ret);
+
spin_unlock(&delayed_refs->lock);
return 0;
}
@@ -587,7 +836,7 @@ btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr)
struct btrfs_delayed_ref_root *delayed_refs;
delayed_refs = &trans->transaction->delayed_refs;
- ref = tree_search(&delayed_refs->root, bytenr, (u64)-1, NULL);
+ ref = find_ref_head(&delayed_refs->root, bytenr, NULL);
if (ref)
return btrfs_delayed_node_to_head(ref);
return NULL;
@@ -603,6 +852,7 @@ btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr)
*
* It is the same as doing a ref add and delete in two separate calls.
*/
+#if 0
int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans,
u64 bytenr, u64 num_bytes, u64 orig_parent,
u64 parent, u64 orig_ref_root, u64 ref_root,
@@ -666,3 +916,4 @@ int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans,
spin_unlock(&delayed_refs->lock);
return 0;
}
+#endif