/* * First add a ref and then drop it, make sure we get a head ref with a * 0 total ref mod and no nodes.
*/ if (type == BTRFS_REF_METADATA) {
node_check.type = BTRFS_TREE_BLOCK_REF_KEY;
node_check.owner = FAKE_LEVEL;
btrfs_init_tree_ref(&ref, FAKE_LEVEL, FAKE_ROOT_OBJECTID, false);
} else {
node_check.type = BTRFS_EXTENT_DATA_REF_KEY;
node_check.owner = FAKE_INO;
node_check.offset = FAKE_FILE_OFFSET;
btrfs_init_data_ref(&ref, FAKE_INO, FAKE_FILE_OFFSET,
FAKE_ROOT_OBJECTID, true);
}
if (type == BTRFS_REF_METADATA)
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); else
ret = btrfs_add_delayed_data_ref(trans, &ref, 0); if (ret) {
test_err("failed ref action %d", ret); return ret;
}
ref.action = BTRFS_DROP_DELAYED_REF; if (type == BTRFS_REF_METADATA)
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); else
ret = btrfs_add_delayed_data_ref(trans, &ref, 0); if (ret) {
test_err("failed ref action %d", ret); goto out;
}
head = btrfs_select_ref_head(fs_info, &trans->transaction->delayed_refs); if (IS_ERR_OR_NULL(head)) { if (IS_ERR(head))
test_err("failed to select delayed ref head: %ld",
PTR_ERR(head)); else
test_err("failed to find delayed ref head"); goto out;
}
ret = -EINVAL; if (validate_ref_head(head, &head_check)) {
test_err("single add and drop failed"); goto out;
}
spin_lock(&head->lock);
node = btrfs_select_delayed_ref(head);
spin_unlock(&head->lock); if (node) {
test_err("found node when none should exist"); goto out;
}
delete_delayed_ref_head(trans, head);
head = NULL;
/* * Add a ref, then add another ref, make sure we get a head ref with a * 2 total ref mod and 1 node.
*/
ref.action = BTRFS_ADD_DELAYED_REF; if (type == BTRFS_REF_METADATA)
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); else
ret = btrfs_add_delayed_data_ref(trans, &ref, 0); if (ret) {
test_err("failed ref action %d", ret); goto out;
}
if (type == BTRFS_REF_METADATA)
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); else
ret = btrfs_add_delayed_data_ref(trans, &ref, 0); if (ret) {
test_err("failed ref action %d", ret); goto out;
}
head = btrfs_select_ref_head(fs_info, &trans->transaction->delayed_refs); if (IS_ERR_OR_NULL(head)) { if (IS_ERR(head))
test_err("failed to select delayed ref head: %ld",
PTR_ERR(head)); else
test_err("failed to find delayed ref head"); goto out;
}
head_check.ref_mod = 2;
head_check.total_ref_mod = 2;
ret = -EINVAL; if (validate_ref_head(head, &head_check)) {
test_err("double add failed"); goto out;
}
spin_lock(&head->lock);
node = btrfs_select_delayed_ref(head);
spin_unlock(&head->lock); if (!node) {
test_err("failed to select delayed ref"); goto out;
}
if (validate_ref_node(node, &node_check)) {
test_err("node check failed"); goto out;
}
delete_delayed_ref_node(head, node);
spin_lock(&head->lock);
node = btrfs_select_delayed_ref(head);
spin_unlock(&head->lock); if (node) {
test_err("found node when none should exist"); goto out;
}
delete_delayed_ref_head(trans, head);
head = NULL;
/* Add two drop refs, make sure they are merged properly. */
ref.action = BTRFS_DROP_DELAYED_REF; if (type == BTRFS_REF_METADATA)
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); else
ret = btrfs_add_delayed_data_ref(trans, &ref, 0); if (ret) {
test_err("failed ref action %d", ret); goto out;
}
if (type == BTRFS_REF_METADATA)
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); else
ret = btrfs_add_delayed_data_ref(trans, &ref, 0); if (ret) {
test_err("failed ref action %d", ret); goto out;
}
head = btrfs_select_ref_head(fs_info, &trans->transaction->delayed_refs); if (IS_ERR_OR_NULL(head)) { if (IS_ERR(head))
test_err("failed to select delayed ref head: %ld",
PTR_ERR(head)); else
test_err("failed to find delayed ref head"); goto out;
}
head_check.ref_mod = -2;
head_check.total_ref_mod = -2;
ret = -EINVAL; if (validate_ref_head(head, &head_check)) {
test_err("double drop failed"); goto out;
}
node_check.action = BTRFS_DROP_DELAYED_REF;
spin_lock(&head->lock);
node = btrfs_select_delayed_ref(head);
spin_unlock(&head->lock); if (!node) {
test_err("failed to select delayed ref"); goto out;
}
if (validate_ref_node(node, &node_check)) {
test_err("node check failed"); goto out;
}
delete_delayed_ref_node(head, node);
spin_lock(&head->lock);
node = btrfs_select_delayed_ref(head);
spin_unlock(&head->lock); if (node) {
test_err("found node when none should exist"); goto out;
}
delete_delayed_ref_head(trans, head);
head = NULL;
/* Add multiple refs, then drop until we go negative again. */
ref.action = BTRFS_ADD_DELAYED_REF; for (int i = 0; i < 10; i++) { if (type == BTRFS_REF_METADATA)
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); else
ret = btrfs_add_delayed_data_ref(trans, &ref, 0); if (ret) {
test_err("failed ref action %d", ret); goto out;
}
}
ref.action = BTRFS_DROP_DELAYED_REF; for (int i = 0; i < 12; i++) { if (type == BTRFS_REF_METADATA)
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); else
ret = btrfs_add_delayed_data_ref(trans, &ref, 0); if (ret) {
test_err("failed ref action %d", ret); goto out;
}
}
head = btrfs_select_ref_head(fs_info, &trans->transaction->delayed_refs); if (IS_ERR_OR_NULL(head)) { if (IS_ERR(head))
test_err("failed to select delayed ref head: %ld",
PTR_ERR(head)); else
test_err("failed to find delayed ref head");
ret = -EINVAL; goto out;
}
head_check.ref_mod = -2;
head_check.total_ref_mod = -2;
ret = -EINVAL; if (validate_ref_head(head, &head_check)) {
test_err("double drop failed"); goto out;
}
spin_lock(&head->lock);
node = btrfs_select_delayed_ref(head);
spin_unlock(&head->lock); if (!node) {
test_err("failed to select delayed ref"); goto out;
}
if (validate_ref_node(node, &node_check)) {
test_err("node check failed"); goto out;
}
delete_delayed_ref_node(head, node);
spin_lock(&head->lock);
node = btrfs_select_delayed_ref(head);
spin_unlock(&head->lock); if (node) {
test_err("found node when none should exist"); goto out;
}
delete_delayed_ref_head(trans, head);
head = NULL;
/* Drop multiple refs, then add until we go positive again. */
ref.action = BTRFS_DROP_DELAYED_REF; for (int i = 0; i < 10; i++) { if (type == BTRFS_REF_METADATA)
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); else
ret = btrfs_add_delayed_data_ref(trans, &ref, 0); if (ret) {
test_err("failed ref action %d", ret); goto out;
}
}
ref.action = BTRFS_ADD_DELAYED_REF; for (int i = 0; i < 12; i++) { if (type == BTRFS_REF_METADATA)
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); else
ret = btrfs_add_delayed_data_ref(trans, &ref, 0); if (ret) {
test_err("failed ref action %d", ret); goto out;
}
}
head = btrfs_select_ref_head(fs_info, &trans->transaction->delayed_refs); if (IS_ERR_OR_NULL(head)) { if (IS_ERR(head))
test_err("failed to select delayed ref head: %ld",
PTR_ERR(head)); else
test_err("failed to find delayed ref head");
ret = -EINVAL; goto out;
}
head_check.ref_mod = 2;
head_check.total_ref_mod = 2;
ret = -EINVAL; if (validate_ref_head(head, &head_check)) {
test_err("add and drop to positive failed"); goto out;
}
node_check.action = BTRFS_ADD_DELAYED_REF;
spin_lock(&head->lock);
node = btrfs_select_delayed_ref(head);
spin_unlock(&head->lock); if (!node) {
test_err("failed to select delayed ref"); goto out;
}
if (validate_ref_node(node, &node_check)) {
test_err("node check failed"); goto out;
}
delete_delayed_ref_node(head, node);
spin_lock(&head->lock);
node = btrfs_select_delayed_ref(head);
spin_unlock(&head->lock); if (node) {
test_err("found node when none should exist"); goto out;
}
delete_delayed_ref_head(trans, head);
head = NULL;
/* * Add a bunch of refs with different roots and parents, then drop them * all, make sure everything is properly merged.
*/
ref.action = BTRFS_ADD_DELAYED_REF; for (int i = 0; i < 50; i++) { if (!(i % 2)) {
ref.parent = 0;
ref.ref_root = FAKE_ROOT_OBJECTID + i;
} else {
ref.parent = FAKE_PARENT + (i * fs_info->nodesize);
} if (type == BTRFS_REF_METADATA)
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); else
ret = btrfs_add_delayed_data_ref(trans, &ref, 0); if (ret) {
test_err("failed ref action %d", ret); goto out;
}
}
ref.action = BTRFS_DROP_DELAYED_REF; for (int i = 0; i < 50; i++) { if (!(i % 2)) {
ref.parent = 0;
ref.ref_root = FAKE_ROOT_OBJECTID + i;
} else {
ref.parent = FAKE_PARENT + (i * fs_info->nodesize);
} if (type == BTRFS_REF_METADATA)
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); else
ret = btrfs_add_delayed_data_ref(trans, &ref, 0); if (ret) {
test_err("failed ref action %d", ret); goto out;
}
}
head = btrfs_select_ref_head(fs_info, &trans->transaction->delayed_refs); if (IS_ERR_OR_NULL(head)) { if (IS_ERR(head))
test_err("failed to select delayed ref head: %ld",
PTR_ERR(head)); else
test_err("failed to find delayed ref head");
ret = -EINVAL; goto out;
}
head_check.ref_mod = 0;
head_check.total_ref_mod = 0;
ret = -EINVAL; if (validate_ref_head(head, &head_check)) {
test_err("add and drop multiple failed"); goto out;
}
spin_lock(&head->lock);
node = btrfs_select_delayed_ref(head);
spin_unlock(&head->lock); if (node) {
test_err("found node when none should exist"); goto out;
}
ret = 0;
out: if (!IS_ERR_OR_NULL(head))
btrfs_unselect_ref_head(&trans->transaction->delayed_refs, head);
btrfs_destroy_delayed_refs(trans->transaction); return ret;
}
/* Add the drop first. */
btrfs_init_tree_ref(&ref, FAKE_LEVEL, FAKE_ROOT_OBJECTID, false);
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); if (ret) {
test_err("failed ref action %d", ret); return ret;
}
/* * Now add the add, and make it a different root so it's logically later * in the rb tree.
*/
ref.action = BTRFS_ADD_DELAYED_REF;
ref.ref_root = FAKE_ROOT_OBJECTID + 1;
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); if (ret) {
test_err("failed ref action %d", ret); goto out;
}
head = btrfs_select_ref_head(fs_info, delayed_refs); if (IS_ERR_OR_NULL(head)) { if (IS_ERR(head))
test_err("failed to select delayed ref head: %ld",
PTR_ERR(head)); else
test_err("failed to find delayed ref head");
ret = -EINVAL;
head = NULL; goto out;
}
ret = -EINVAL; if (validate_ref_head(head, &head_check)) {
test_err("head check failed"); goto out;
}
spin_lock(&head->lock);
node = btrfs_select_delayed_ref(head);
spin_unlock(&head->lock); if (!node) {
test_err("failed to select delayed ref"); goto out;
}
/* * Now we're going to do the same thing, but we're going to have an add * that gets deleted because of a merge, and make sure we still have * another add in place.
*/
ref.action = BTRFS_DROP_DELAYED_REF;
ref.ref_root = FAKE_ROOT_OBJECTID;
ret = btrfs_add_delayed_tree_ref(trans, &ref, NULL); if (ret) {
test_err("failed ref action %d", ret); goto out;
}
head = btrfs_select_ref_head(fs_info, delayed_refs); if (IS_ERR_OR_NULL(head)) { if (IS_ERR(head))
test_err("failed to select delayed ref head: %ld",
PTR_ERR(head)); else
test_err("failed to find delayed ref head");
ret = -EINVAL;
head = NULL; goto out;
}
ret = -EINVAL; if (validate_ref_head(head, &head_check)) {
test_err("head check failed"); goto out;
}
spin_lock(&head->lock);
node = btrfs_select_delayed_ref(head);
spin_unlock(&head->lock); if (!node) {
test_err("failed to select delayed ref"); goto out;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.