1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2013 Fusion IO.  All rights reserved.
4  */
5 
6 #include <linux/slab.h>
7 #include "btrfs-tests.h"
8 #include "../ctree.h"
9 #include "../extent_io.h"
10 #include "../disk-io.h"
11 
12 static int test_btrfs_split_item(u32 sectorsize, u32 nodesize)
13 {
14 	struct btrfs_fs_info *fs_info;
15 	struct btrfs_path *path = NULL;
16 	struct btrfs_root *root = NULL;
17 	struct extent_buffer *eb;
18 	struct btrfs_item *item;
19 	char *value = "mary had a little lamb";
20 	char *split1 = "mary had a little";
21 	char *split2 = " lamb";
22 	char *split3 = "mary";
23 	char *split4 = " had a little";
24 	char buf[32];
25 	struct btrfs_key key;
26 	u32 value_len = strlen(value);
27 	int ret = 0;
28 
29 	test_msg("running btrfs_split_item tests");
30 
31 	fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize);
32 	if (!fs_info) {
33 		test_std_err(TEST_ALLOC_FS_INFO);
34 		return -ENOMEM;
35 	}
36 
37 	root = btrfs_alloc_dummy_root(fs_info);
38 	if (IS_ERR(root)) {
39 		test_std_err(TEST_ALLOC_ROOT);
40 		ret = PTR_ERR(root);
41 		goto out;
42 	}
43 
44 	path = btrfs_alloc_path();
45 	if (!path) {
46 		test_std_err(TEST_ALLOC_PATH);
47 		ret = -ENOMEM;
48 		goto out;
49 	}
50 
51 	path->nodes[0] = eb = alloc_dummy_extent_buffer(fs_info, nodesize);
52 	if (!eb) {
53 		test_std_err(TEST_ALLOC_EXTENT_BUFFER);
54 		ret = -ENOMEM;
55 		goto out;
56 	}
57 	path->slots[0] = 0;
58 
59 	key.objectid = 0;
60 	key.type = BTRFS_EXTENT_CSUM_KEY;
61 	key.offset = 0;
62 
63 	setup_items_for_insert(root, path, &key, &value_len, 1);
64 	item = btrfs_item_nr(0);
65 	write_extent_buffer(eb, value, btrfs_item_ptr_offset(eb, 0),
66 			    value_len);
67 
68 	key.offset = 3;
69 
70 	/*
71 	 * Passing NULL trans here should be safe because we have plenty of
72 	 * space in this leaf to split the item without having to split the
73 	 * leaf.
74 	 */
75 	ret = btrfs_split_item(NULL, root, path, &key, 17);
76 	if (ret) {
77 		test_err("split item failed %d", ret);
78 		goto out;
79 	}
80 
81 	/*
82 	 * Read the first slot, it should have the original key and contain only
83 	 * 'mary had a little'
84 	 */
85 	btrfs_item_key_to_cpu(eb, &key, 0);
86 	if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
87 	    key.offset != 0) {
88 		test_err("invalid key at slot 0");
89 		ret = -EINVAL;
90 		goto out;
91 	}
92 
93 	item = btrfs_item_nr(0);
94 	if (btrfs_item_size(eb, item) != strlen(split1)) {
95 		test_err("invalid len in the first split");
96 		ret = -EINVAL;
97 		goto out;
98 	}
99 
100 	read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 0),
101 			   strlen(split1));
102 	if (memcmp(buf, split1, strlen(split1))) {
103 		test_err(
104 "data in the buffer doesn't match what it should in the first split have='%.*s' want '%s'",
105 			 (int)strlen(split1), buf, split1);
106 		ret = -EINVAL;
107 		goto out;
108 	}
109 
110 	btrfs_item_key_to_cpu(eb, &key, 1);
111 	if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
112 	    key.offset != 3) {
113 		test_err("invalid key at slot 1");
114 		ret = -EINVAL;
115 		goto out;
116 	}
117 
118 	item = btrfs_item_nr(1);
119 	if (btrfs_item_size(eb, item) != strlen(split2)) {
120 		test_err("invalid len in the second split");
121 		ret = -EINVAL;
122 		goto out;
123 	}
124 
125 	read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 1),
126 			   strlen(split2));
127 	if (memcmp(buf, split2, strlen(split2))) {
128 		test_err(
129 	"data in the buffer doesn't match what it should in the second split");
130 		ret = -EINVAL;
131 		goto out;
132 	}
133 
134 	key.offset = 1;
135 	/* Do it again so we test memmoving the other items in the leaf */
136 	ret = btrfs_split_item(NULL, root, path, &key, 4);
137 	if (ret) {
138 		test_err("second split item failed %d", ret);
139 		goto out;
140 	}
141 
142 	btrfs_item_key_to_cpu(eb, &key, 0);
143 	if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
144 	    key.offset != 0) {
145 		test_err("invalid key at slot 0");
146 		ret = -EINVAL;
147 		goto out;
148 	}
149 
150 	item = btrfs_item_nr(0);
151 	if (btrfs_item_size(eb, item) != strlen(split3)) {
152 		test_err("invalid len in the first split");
153 		ret = -EINVAL;
154 		goto out;
155 	}
156 
157 	read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 0),
158 			   strlen(split3));
159 	if (memcmp(buf, split3, strlen(split3))) {
160 		test_err(
161 	"data in the buffer doesn't match what it should in the third split");
162 		ret = -EINVAL;
163 		goto out;
164 	}
165 
166 	btrfs_item_key_to_cpu(eb, &key, 1);
167 	if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
168 	    key.offset != 1) {
169 		test_err("invalid key at slot 1");
170 		ret = -EINVAL;
171 		goto out;
172 	}
173 
174 	item = btrfs_item_nr(1);
175 	if (btrfs_item_size(eb, item) != strlen(split4)) {
176 		test_err("invalid len in the second split");
177 		ret = -EINVAL;
178 		goto out;
179 	}
180 
181 	read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 1),
182 			   strlen(split4));
183 	if (memcmp(buf, split4, strlen(split4))) {
184 		test_err(
185 	"data in the buffer doesn't match what it should in the fourth split");
186 		ret = -EINVAL;
187 		goto out;
188 	}
189 
190 	btrfs_item_key_to_cpu(eb, &key, 2);
191 	if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
192 	    key.offset != 3) {
193 		test_err("invalid key at slot 2");
194 		ret = -EINVAL;
195 		goto out;
196 	}
197 
198 	item = btrfs_item_nr(2);
199 	if (btrfs_item_size(eb, item) != strlen(split2)) {
200 		test_err("invalid len in the second split");
201 		ret = -EINVAL;
202 		goto out;
203 	}
204 
205 	read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 2),
206 			   strlen(split2));
207 	if (memcmp(buf, split2, strlen(split2))) {
208 		test_err(
209 	"data in the buffer doesn't match what it should in the last chunk");
210 		ret = -EINVAL;
211 		goto out;
212 	}
213 out:
214 	btrfs_free_path(path);
215 	btrfs_free_dummy_root(root);
216 	btrfs_free_dummy_fs_info(fs_info);
217 	return ret;
218 }
219 
220 int btrfs_test_extent_buffer_operations(u32 sectorsize, u32 nodesize)
221 {
222 	test_msg("running extent buffer operation tests");
223 	return test_btrfs_split_item(sectorsize, nodesize);
224 }
225