@@ -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);
}
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(-)