diff mbox series

[09/11] btrfs: selftests: add a test for delete_one_dir_name

Message ID af91dc5a529a81bfb70b6c3336700c7ab06aa71c.1646692474.git.josef@toxicpanda.com (mailing list archive)
State New, archived
Headers show
Series btrfs: add snapshot_id to btrfs_header and root_item | expand

Commit Message

Josef Bacik March 7, 2022, 10:36 p.m. UTC
Because I can't do simple math I was convinced btrfs_delete_one_dir_name
was doing the wrong thing, so I wrote a self test to validate my theory.
I turned out to be wrong, but it's a valuable test to have for the
future.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 fs/btrfs/tests/extent-buffer-tests.c | 170 ++++++++++++++++++++++++++-
 1 file changed, 169 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/fs/btrfs/tests/extent-buffer-tests.c b/fs/btrfs/tests/extent-buffer-tests.c
index 51a8b075c259..131495ffad12 100644
--- a/fs/btrfs/tests/extent-buffer-tests.c
+++ b/fs/btrfs/tests/extent-buffer-tests.c
@@ -8,6 +8,7 @@ 
 #include "../ctree.h"
 #include "../extent_io.h"
 #include "../disk-io.h"
+#include "../transaction.h"
 
 static int test_btrfs_split_item(u32 sectorsize, u32 nodesize)
 {
@@ -210,8 +211,175 @@  static int test_btrfs_split_item(u32 sectorsize, u32 nodesize)
 	return ret;
 }
 
+static int test_delete_one_dir_name(u32 sectorsize, u32 nodesize)
+{
+	struct btrfs_fs_info *fs_info;
+	struct btrfs_path *path = NULL;
+	struct btrfs_root *root = NULL;
+	struct extent_buffer *eb;
+	struct btrfs_dir_item *dir_item;
+	char *ptr;
+	struct btrfs_trans_handle trans;
+	char name_buf[6];
+	struct btrfs_key key;
+	u32 len = 0;
+	int ret = 0;
+	int i;
+
+	test_msg("running btrfs_delete_one_dir_name tests");
+
+	fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize);
+	if (!fs_info) {
+		test_std_err(TEST_ALLOC_FS_INFO);
+		return -ENOMEM;
+	}
+
+	root = btrfs_alloc_dummy_root(fs_info);
+	if (IS_ERR(root)) {
+		test_std_err(TEST_ALLOC_ROOT);
+		ret = PTR_ERR(root);
+		goto out;
+	}
+
+	path = btrfs_alloc_path();
+	if (!path) {
+		test_std_err(TEST_ALLOC_PATH);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	path->nodes[0] = eb = alloc_dummy_extent_buffer(fs_info, nodesize);
+	if (!eb) {
+		test_std_err(TEST_ALLOC_EXTENT_BUFFER);
+		ret = -ENOMEM;
+		goto out;
+	}
+	path->slots[0] = 0;
+
+	key.objectid = 0;
+	key.type = BTRFS_DIR_ITEM_KEY;
+	key.offset = 0;
+
+	btrfs_init_dummy_trans(&trans, fs_info);
+
+	/*
+	 * We are going to have 5 names, a, bb, ccc, dddd, eeeee, so the sizes
+	 * are the dir_item + i + 1.
+	 */
+	for (i = 0; i < 5; i++)
+		len += sizeof(struct btrfs_dir_item) + i + 1;
+
+	btrfs_setup_item_for_insert(root, path, &key, len);
+
+	ptr = btrfs_item_ptr(eb, path->slots[0], char);
+	for (i = 0; i < 5; i++) {
+		unsigned long name_ptr;
+
+		memset(name_buf, 'a' + i, i + 1);
+		dir_item = (struct btrfs_dir_item *)ptr;
+		btrfs_set_dir_type(eb, dir_item, i);
+		btrfs_set_dir_data_len(eb, dir_item, 0);
+		btrfs_set_dir_name_len(eb, dir_item, i + 1);
+		name_ptr = (unsigned long)(dir_item + 1);
+		write_extent_buffer(eb, name_buf, name_ptr, i + 1);
+		ptr += sizeof(struct btrfs_dir_item) + i + 1;
+	}
+
+	if (btrfs_item_size(eb, 0) != len) {
+		test_err("invalid len after initial start up");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Delete the ccc dir_name */
+	ptr = btrfs_item_ptr(eb, path->slots[0], char);
+	for (i = 0; i < 2; i++)
+		ptr += sizeof(struct btrfs_dir_item) + i + 1;
+	dir_item = (struct btrfs_dir_item *)ptr;
+	if (btrfs_dir_type(eb, dir_item) != 2) {
+		test_err("got the wrong dir type???\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = btrfs_delete_one_dir_name(&trans, root, path, dir_item);
+	if (ret) {
+		test_err("got %d from btrfs_delete_one_dir_name", ret);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	len -= sizeof(struct btrfs_dir_item) + 3;
+	if (btrfs_item_size(eb, 0) != len) {
+		test_err("invalid len after delete");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ptr = btrfs_item_ptr(eb, path->slots[0], char);
+	for (i = 0; i < 4; i++) {
+		int real_index = i;
+		int c;
+
+		/*
+		 * We deleted ccc, which was index 2, so increase real_index by
+		 * 1 so we get the right value.
+		 */
+		if (i >= 2)
+			real_index++;
+
+		dir_item = (struct btrfs_dir_item *)ptr;
+		if (btrfs_dir_type(eb, dir_item) != real_index) {
+			test_err("dir item %d is mangled, dir_type is %d expected %d",
+				 i, btrfs_dir_type(eb, dir_item), real_index);
+			ret = -EINVAL;
+			goto out;
+		}
+
+		if (btrfs_dir_data_len(eb, dir_item) != 0) {
+			test_err("dir item %d is mangled, data_len is %d expected 0",
+				 i, btrfs_dir_data_len(eb, dir_item));
+			ret = -EINVAL;
+			goto out;
+		}
+
+		if (btrfs_dir_name_len(eb, dir_item) != real_index + 1) {
+			test_err("dir item %d is mangled, name_len is %d expected %d",
+				 i, btrfs_dir_name_len(eb, dir_item),
+				 real_index + 1);
+			ret = -EINVAL;
+			goto out;
+		}
+
+		read_extent_buffer(eb, name_buf, (unsigned long)(dir_item + 1),
+				   btrfs_dir_name_len(eb, dir_item));
+		for (c = 0; c < real_index + 1; c++) {
+			if (name_buf[c] != 'a' + real_index) {
+				test_err(
+		"dir item name %d is mangled, index is %d val is %c wanted %c",
+					 i, c, name_buf[c], 'a' + real_index);
+				ret = -EINVAL;
+				goto out;
+			}
+		}
+
+		ptr += sizeof(struct btrfs_dir_item) + real_index + 1;
+	}
+out:
+	btrfs_free_path(path);
+	btrfs_free_dummy_root(root);
+	btrfs_free_dummy_fs_info(fs_info);
+	return ret;
+}
+
 int btrfs_test_extent_buffer_operations(u32 sectorsize, u32 nodesize)
 {
+	int ret;
+
 	test_msg("running extent buffer operation tests");
-	return test_btrfs_split_item(sectorsize, nodesize);
+	ret = test_btrfs_split_item(sectorsize, nodesize);
+	if (ret)
+		return ret;
+	test_msg("running delete dir name etests");
+	return test_delete_one_dir_name(sectorsize, nodesize);
 }