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 | #include "../accessors.h" |
12 | |
13 | static int test_btrfs_split_item(u32 sectorsize, u32 nodesize) |
14 | { |
15 | struct btrfs_fs_info *fs_info; |
16 | struct btrfs_path *path = NULL; |
17 | struct btrfs_root *root = NULL; |
18 | struct extent_buffer *eb; |
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(ptr: root)) { |
39 | test_std_err(TEST_ALLOC_ROOT); |
40 | ret = PTR_ERR(ptr: 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 | eb = alloc_dummy_extent_buffer(fs_info, start: nodesize); |
52 | path->nodes[0] = eb; |
53 | if (!eb) { |
54 | test_std_err(TEST_ALLOC_EXTENT_BUFFER); |
55 | ret = -ENOMEM; |
56 | goto out; |
57 | } |
58 | path->slots[0] = 0; |
59 | |
60 | key.objectid = 0; |
61 | key.type = BTRFS_EXTENT_CSUM_KEY; |
62 | key.offset = 0; |
63 | |
64 | /* |
65 | * Passing a NULL trans handle is fine here, we have a dummy root eb |
66 | * and the tree is a single node (level 0). |
67 | */ |
68 | btrfs_setup_item_for_insert(NULL, root, path, key: &key, data_size: value_len); |
69 | write_extent_buffer(eb, src: value, btrfs_item_ptr_offset(eb, 0), |
70 | len: value_len); |
71 | |
72 | key.offset = 3; |
73 | |
74 | /* |
75 | * Passing NULL trans here should be safe because we have plenty of |
76 | * space in this leaf to split the item without having to split the |
77 | * leaf. |
78 | */ |
79 | ret = btrfs_split_item(NULL, root, path, new_key: &key, split_offset: 17); |
80 | if (ret) { |
81 | test_err("split item failed %d" , ret); |
82 | goto out; |
83 | } |
84 | |
85 | /* |
86 | * Read the first slot, it should have the original key and contain only |
87 | * 'mary had a little' |
88 | */ |
89 | btrfs_item_key_to_cpu(eb, cpu_key: &key, nr: 0); |
90 | if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY || |
91 | key.offset != 0) { |
92 | test_err("invalid key at slot 0" ); |
93 | ret = -EINVAL; |
94 | goto out; |
95 | } |
96 | |
97 | if (btrfs_item_size(eb, slot: 0) != strlen(split1)) { |
98 | test_err("invalid len in the first split" ); |
99 | ret = -EINVAL; |
100 | goto out; |
101 | } |
102 | |
103 | read_extent_buffer(eb, dst: buf, btrfs_item_ptr_offset(eb, 0), |
104 | strlen(split1)); |
105 | if (memcmp(p: buf, q: split1, strlen(split1))) { |
106 | test_err( |
107 | "data in the buffer doesn't match what it should in the first split have='%.*s' want '%s'" , |
108 | (int)strlen(split1), buf, split1); |
109 | ret = -EINVAL; |
110 | goto out; |
111 | } |
112 | |
113 | btrfs_item_key_to_cpu(eb, cpu_key: &key, nr: 1); |
114 | if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY || |
115 | key.offset != 3) { |
116 | test_err("invalid key at slot 1" ); |
117 | ret = -EINVAL; |
118 | goto out; |
119 | } |
120 | |
121 | if (btrfs_item_size(eb, slot: 1) != strlen(split2)) { |
122 | test_err("invalid len in the second split" ); |
123 | ret = -EINVAL; |
124 | goto out; |
125 | } |
126 | |
127 | read_extent_buffer(eb, dst: buf, btrfs_item_ptr_offset(eb, 1), |
128 | strlen(split2)); |
129 | if (memcmp(p: buf, q: split2, strlen(split2))) { |
130 | test_err( |
131 | "data in the buffer doesn't match what it should in the second split" ); |
132 | ret = -EINVAL; |
133 | goto out; |
134 | } |
135 | |
136 | key.offset = 1; |
137 | /* Do it again so we test memmoving the other items in the leaf */ |
138 | ret = btrfs_split_item(NULL, root, path, new_key: &key, split_offset: 4); |
139 | if (ret) { |
140 | test_err("second split item failed %d" , ret); |
141 | goto out; |
142 | } |
143 | |
144 | btrfs_item_key_to_cpu(eb, cpu_key: &key, nr: 0); |
145 | if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY || |
146 | key.offset != 0) { |
147 | test_err("invalid key at slot 0" ); |
148 | ret = -EINVAL; |
149 | goto out; |
150 | } |
151 | |
152 | if (btrfs_item_size(eb, slot: 0) != strlen(split3)) { |
153 | test_err("invalid len in the first split" ); |
154 | ret = -EINVAL; |
155 | goto out; |
156 | } |
157 | |
158 | read_extent_buffer(eb, dst: buf, btrfs_item_ptr_offset(eb, 0), |
159 | strlen(split3)); |
160 | if (memcmp(p: buf, q: split3, strlen(split3))) { |
161 | test_err( |
162 | "data in the buffer doesn't match what it should in the third split" ); |
163 | ret = -EINVAL; |
164 | goto out; |
165 | } |
166 | |
167 | btrfs_item_key_to_cpu(eb, cpu_key: &key, nr: 1); |
168 | if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY || |
169 | key.offset != 1) { |
170 | test_err("invalid key at slot 1" ); |
171 | ret = -EINVAL; |
172 | goto out; |
173 | } |
174 | |
175 | if (btrfs_item_size(eb, slot: 1) != strlen(split4)) { |
176 | test_err("invalid len in the second split" ); |
177 | ret = -EINVAL; |
178 | goto out; |
179 | } |
180 | |
181 | read_extent_buffer(eb, dst: buf, btrfs_item_ptr_offset(eb, 1), |
182 | strlen(split4)); |
183 | if (memcmp(p: buf, q: 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, cpu_key: &key, nr: 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 | if (btrfs_item_size(eb, slot: 2) != strlen(split2)) { |
199 | test_err("invalid len in the second split" ); |
200 | ret = -EINVAL; |
201 | goto out; |
202 | } |
203 | |
204 | read_extent_buffer(eb, dst: buf, btrfs_item_ptr_offset(eb, 2), |
205 | strlen(split2)); |
206 | if (memcmp(p: buf, q: split2, strlen(split2))) { |
207 | test_err( |
208 | "data in the buffer doesn't match what it should in the last chunk" ); |
209 | ret = -EINVAL; |
210 | goto out; |
211 | } |
212 | out: |
213 | btrfs_free_path(p: path); |
214 | btrfs_free_dummy_root(root); |
215 | btrfs_free_dummy_fs_info(fs_info); |
216 | return ret; |
217 | } |
218 | |
219 | int btrfs_test_extent_buffer_operations(u32 sectorsize, u32 nodesize) |
220 | { |
221 | test_msg("running extent buffer operation tests" ); |
222 | return test_btrfs_split_item(sectorsize, nodesize); |
223 | } |
224 | |