Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2#ifdef CONFIG_BCACHEFS_TESTS
3
4#include "bcachefs.h"
5#include "btree_update.h"
6#include "journal_reclaim.h"
7#include "snapshot.h"
8#include "tests.h"
9
10#include "linux/kthread.h"
11#include "linux/random.h"
12
13static void delete_test_keys(struct bch_fs *c)
14{
15 int ret;
16
17 ret = bch2_btree_delete_range(c, BTREE_ID_extents,
18 SPOS(0, 0, U32_MAX),
19 POS(0, U64_MAX),
20 0, NULL);
21 BUG_ON(ret);
22
23 ret = bch2_btree_delete_range(c, BTREE_ID_xattrs,
24 SPOS(0, 0, U32_MAX),
25 POS(0, U64_MAX),
26 0, NULL);
27 BUG_ON(ret);
28}
29
30/* unit tests */
31
32static int test_delete(struct bch_fs *c, u64 nr)
33{
34 struct btree_trans *trans = bch2_trans_get(c);
35 struct btree_iter iter;
36 struct bkey_i_cookie k;
37 int ret;
38
39 bkey_cookie_init(&k.k_i);
40 k.k.p.snapshot = U32_MAX;
41
42 bch2_trans_iter_init(trans, &iter, BTREE_ID_xattrs, k.k.p,
43 BTREE_ITER_INTENT);
44
45 ret = commit_do(trans, NULL, NULL, 0,
46 bch2_btree_iter_traverse(&iter) ?:
47 bch2_trans_update(trans, &iter, &k.k_i, 0));
48 bch_err_msg(c, ret, "update error");
49 if (ret)
50 goto err;
51
52 pr_info("deleting once");
53 ret = commit_do(trans, NULL, NULL, 0,
54 bch2_btree_iter_traverse(&iter) ?:
55 bch2_btree_delete_at(trans, &iter, 0));
56 bch_err_msg(c, ret, "delete error (first)");
57 if (ret)
58 goto err;
59
60 pr_info("deleting twice");
61 ret = commit_do(trans, NULL, NULL, 0,
62 bch2_btree_iter_traverse(&iter) ?:
63 bch2_btree_delete_at(trans, &iter, 0));
64 bch_err_msg(c, ret, "delete error (second)");
65 if (ret)
66 goto err;
67err:
68 bch2_trans_iter_exit(trans, &iter);
69 bch2_trans_put(trans);
70 return ret;
71}
72
73static int test_delete_written(struct bch_fs *c, u64 nr)
74{
75 struct btree_trans *trans = bch2_trans_get(c);
76 struct btree_iter iter;
77 struct bkey_i_cookie k;
78 int ret;
79
80 bkey_cookie_init(&k.k_i);
81 k.k.p.snapshot = U32_MAX;
82
83 bch2_trans_iter_init(trans, &iter, BTREE_ID_xattrs, k.k.p,
84 BTREE_ITER_INTENT);
85
86 ret = commit_do(trans, NULL, NULL, 0,
87 bch2_btree_iter_traverse(&iter) ?:
88 bch2_trans_update(trans, &iter, &k.k_i, 0));
89 bch_err_msg(c, ret, "update error");
90 if (ret)
91 goto err;
92
93 bch2_trans_unlock(trans);
94 bch2_journal_flush_all_pins(&c->journal);
95
96 ret = commit_do(trans, NULL, NULL, 0,
97 bch2_btree_iter_traverse(&iter) ?:
98 bch2_btree_delete_at(trans, &iter, 0));
99 bch_err_msg(c, ret, "delete error");
100 if (ret)
101 goto err;
102err:
103 bch2_trans_iter_exit(trans, &iter);
104 bch2_trans_put(trans);
105 return ret;
106}
107
108static int test_iterate(struct bch_fs *c, u64 nr)
109{
110 struct btree_trans *trans = bch2_trans_get(c);
111 struct btree_iter iter = { NULL };
112 struct bkey_s_c k;
113 u64 i;
114 int ret = 0;
115
116 delete_test_keys(c);
117
118 pr_info("inserting test keys");
119
120 for (i = 0; i < nr; i++) {
121 struct bkey_i_cookie ck;
122
123 bkey_cookie_init(&ck.k_i);
124 ck.k.p.offset = i;
125 ck.k.p.snapshot = U32_MAX;
126
127 ret = bch2_btree_insert(c, BTREE_ID_xattrs, &ck.k_i, NULL, 0);
128 bch_err_msg(c, ret, "insert error");
129 if (ret)
130 goto err;
131 }
132
133 pr_info("iterating forwards");
134
135 i = 0;
136
137 ret = for_each_btree_key2_upto(trans, iter, BTREE_ID_xattrs,
138 SPOS(0, 0, U32_MAX), POS(0, U64_MAX),
139 0, k, ({
140 BUG_ON(k.k->p.offset != i++);
141 0;
142 }));
143 bch_err_msg(c, ret, "error iterating forwards");
144 if (ret)
145 goto err;
146
147 BUG_ON(i != nr);
148
149 pr_info("iterating backwards");
150
151 ret = for_each_btree_key_reverse(trans, iter, BTREE_ID_xattrs,
152 SPOS(0, U64_MAX, U32_MAX), 0, k,
153 ({
154 BUG_ON(k.k->p.offset != --i);
155 0;
156 }));
157 bch_err_msg(c, ret, "error iterating backwards");
158 if (ret)
159 goto err;
160
161 BUG_ON(i);
162err:
163 bch2_trans_iter_exit(trans, &iter);
164 bch2_trans_put(trans);
165 return ret;
166}
167
168static int test_iterate_extents(struct bch_fs *c, u64 nr)
169{
170 struct btree_trans *trans = bch2_trans_get(c);
171 struct btree_iter iter = { NULL };
172 struct bkey_s_c k;
173 u64 i;
174 int ret = 0;
175
176 delete_test_keys(c);
177
178 pr_info("inserting test extents");
179
180 for (i = 0; i < nr; i += 8) {
181 struct bkey_i_cookie ck;
182
183 bkey_cookie_init(&ck.k_i);
184 ck.k.p.offset = i + 8;
185 ck.k.p.snapshot = U32_MAX;
186 ck.k.size = 8;
187
188 ret = bch2_btree_insert(c, BTREE_ID_extents, &ck.k_i, NULL, 0);
189 bch_err_msg(c, ret, "insert error");
190 if (ret)
191 goto err;
192 }
193
194 pr_info("iterating forwards");
195
196 i = 0;
197
198 ret = for_each_btree_key2_upto(trans, iter, BTREE_ID_extents,
199 SPOS(0, 0, U32_MAX), POS(0, U64_MAX),
200 0, k, ({
201 BUG_ON(bkey_start_offset(k.k) != i);
202 i = k.k->p.offset;
203 0;
204 }));
205 bch_err_msg(c, ret, "error iterating forwards");
206 if (ret)
207 goto err;
208
209 BUG_ON(i != nr);
210
211 pr_info("iterating backwards");
212
213 ret = for_each_btree_key_reverse(trans, iter, BTREE_ID_extents,
214 SPOS(0, U64_MAX, U32_MAX), 0, k,
215 ({
216 BUG_ON(k.k->p.offset != i);
217 i = bkey_start_offset(k.k);
218 0;
219 }));
220 bch_err_msg(c, ret, "error iterating backwards");
221 if (ret)
222 goto err;
223
224 BUG_ON(i);
225err:
226 bch2_trans_iter_exit(trans, &iter);
227 bch2_trans_put(trans);
228 return ret;
229}
230
231static int test_iterate_slots(struct bch_fs *c, u64 nr)
232{
233 struct btree_trans *trans = bch2_trans_get(c);
234 struct btree_iter iter = { NULL };
235 struct bkey_s_c k;
236 u64 i;
237 int ret = 0;
238
239 delete_test_keys(c);
240
241 pr_info("inserting test keys");
242
243 for (i = 0; i < nr; i++) {
244 struct bkey_i_cookie ck;
245
246 bkey_cookie_init(&ck.k_i);
247 ck.k.p.offset = i * 2;
248 ck.k.p.snapshot = U32_MAX;
249
250 ret = bch2_btree_insert(c, BTREE_ID_xattrs, &ck.k_i, NULL, 0);
251 bch_err_msg(c, ret, "insert error");
252 if (ret)
253 goto err;
254 }
255
256 pr_info("iterating forwards");
257
258 i = 0;
259
260 ret = for_each_btree_key2_upto(trans, iter, BTREE_ID_xattrs,
261 SPOS(0, 0, U32_MAX), POS(0, U64_MAX),
262 0, k, ({
263 BUG_ON(k.k->p.offset != i);
264 i += 2;
265 0;
266 }));
267 bch_err_msg(c, ret, "error iterating forwards");
268 if (ret)
269 goto err;
270
271 BUG_ON(i != nr * 2);
272
273 pr_info("iterating forwards by slots");
274
275 i = 0;
276
277 ret = for_each_btree_key2_upto(trans, iter, BTREE_ID_xattrs,
278 SPOS(0, 0, U32_MAX), POS(0, U64_MAX),
279 BTREE_ITER_SLOTS, k, ({
280 if (i >= nr * 2)
281 break;
282
283 BUG_ON(k.k->p.offset != i);
284 BUG_ON(bkey_deleted(k.k) != (i & 1));
285
286 i++;
287 0;
288 }));
289 if (ret < 0) {
290 bch_err_msg(c, ret, "error iterating forwards by slots");
291 goto err;
292 }
293 ret = 0;
294err:
295 bch2_trans_put(trans);
296 return ret;
297}
298
299static int test_iterate_slots_extents(struct bch_fs *c, u64 nr)
300{
301 struct btree_trans *trans = bch2_trans_get(c);
302 struct btree_iter iter = { NULL };
303 struct bkey_s_c k;
304 u64 i;
305 int ret = 0;
306
307 delete_test_keys(c);
308
309 pr_info("inserting test keys");
310
311 for (i = 0; i < nr; i += 16) {
312 struct bkey_i_cookie ck;
313
314 bkey_cookie_init(&ck.k_i);
315 ck.k.p.offset = i + 16;
316 ck.k.p.snapshot = U32_MAX;
317 ck.k.size = 8;
318
319 ret = bch2_btree_insert(c, BTREE_ID_extents, &ck.k_i, NULL, 0);
320 bch_err_msg(c, ret, "insert error");
321 if (ret)
322 goto err;
323 }
324
325 pr_info("iterating forwards");
326
327 i = 0;
328
329 ret = for_each_btree_key2_upto(trans, iter, BTREE_ID_extents,
330 SPOS(0, 0, U32_MAX), POS(0, U64_MAX),
331 0, k, ({
332 BUG_ON(bkey_start_offset(k.k) != i + 8);
333 BUG_ON(k.k->size != 8);
334 i += 16;
335 0;
336 }));
337 bch_err_msg(c, ret, "error iterating forwards");
338 if (ret)
339 goto err;
340
341 BUG_ON(i != nr);
342
343 pr_info("iterating forwards by slots");
344
345 i = 0;
346
347 ret = for_each_btree_key2_upto(trans, iter, BTREE_ID_extents,
348 SPOS(0, 0, U32_MAX), POS(0, U64_MAX),
349 BTREE_ITER_SLOTS, k, ({
350 if (i == nr)
351 break;
352 BUG_ON(bkey_deleted(k.k) != !(i % 16));
353
354 BUG_ON(bkey_start_offset(k.k) != i);
355 BUG_ON(k.k->size != 8);
356 i = k.k->p.offset;
357 0;
358 }));
359 bch_err_msg(c, ret, "error iterating forwards by slots");
360 if (ret)
361 goto err;
362 ret = 0;
363err:
364 bch2_trans_put(trans);
365 return 0;
366}
367
368/*
369 * XXX: we really want to make sure we've got a btree with depth > 0 for these
370 * tests
371 */
372static int test_peek_end(struct bch_fs *c, u64 nr)
373{
374 struct btree_trans *trans = bch2_trans_get(c);
375 struct btree_iter iter;
376 struct bkey_s_c k;
377
378 bch2_trans_iter_init(trans, &iter, BTREE_ID_xattrs,
379 SPOS(0, 0, U32_MAX), 0);
380
381 lockrestart_do(trans, bkey_err(k = bch2_btree_iter_peek_upto(&iter, POS(0, U64_MAX))));
382 BUG_ON(k.k);
383
384 lockrestart_do(trans, bkey_err(k = bch2_btree_iter_peek_upto(&iter, POS(0, U64_MAX))));
385 BUG_ON(k.k);
386
387 bch2_trans_iter_exit(trans, &iter);
388 bch2_trans_put(trans);
389 return 0;
390}
391
392static int test_peek_end_extents(struct bch_fs *c, u64 nr)
393{
394 struct btree_trans *trans = bch2_trans_get(c);
395 struct btree_iter iter;
396 struct bkey_s_c k;
397
398 bch2_trans_iter_init(trans, &iter, BTREE_ID_extents,
399 SPOS(0, 0, U32_MAX), 0);
400
401 lockrestart_do(trans, bkey_err(k = bch2_btree_iter_peek_upto(&iter, POS(0, U64_MAX))));
402 BUG_ON(k.k);
403
404 lockrestart_do(trans, bkey_err(k = bch2_btree_iter_peek_upto(&iter, POS(0, U64_MAX))));
405 BUG_ON(k.k);
406
407 bch2_trans_iter_exit(trans, &iter);
408 bch2_trans_put(trans);
409 return 0;
410}
411
412/* extent unit tests */
413
414static u64 test_version;
415
416static int insert_test_extent(struct bch_fs *c,
417 u64 start, u64 end)
418{
419 struct bkey_i_cookie k;
420 int ret;
421
422 bkey_cookie_init(&k.k_i);
423 k.k_i.k.p.offset = end;
424 k.k_i.k.p.snapshot = U32_MAX;
425 k.k_i.k.size = end - start;
426 k.k_i.k.version.lo = test_version++;
427
428 ret = bch2_btree_insert(c, BTREE_ID_extents, &k.k_i, NULL, 0);
429 bch_err_fn(c, ret);
430 return ret;
431}
432
433static int __test_extent_overwrite(struct bch_fs *c,
434 u64 e1_start, u64 e1_end,
435 u64 e2_start, u64 e2_end)
436{
437 int ret;
438
439 ret = insert_test_extent(c, e1_start, e1_end) ?:
440 insert_test_extent(c, e2_start, e2_end);
441
442 delete_test_keys(c);
443 return ret;
444}
445
446static int test_extent_overwrite_front(struct bch_fs *c, u64 nr)
447{
448 return __test_extent_overwrite(c, 0, 64, 0, 32) ?:
449 __test_extent_overwrite(c, 8, 64, 0, 32);
450}
451
452static int test_extent_overwrite_back(struct bch_fs *c, u64 nr)
453{
454 return __test_extent_overwrite(c, 0, 64, 32, 64) ?:
455 __test_extent_overwrite(c, 0, 64, 32, 72);
456}
457
458static int test_extent_overwrite_middle(struct bch_fs *c, u64 nr)
459{
460 return __test_extent_overwrite(c, 0, 64, 32, 40);
461}
462
463static int test_extent_overwrite_all(struct bch_fs *c, u64 nr)
464{
465 return __test_extent_overwrite(c, 32, 64, 0, 64) ?:
466 __test_extent_overwrite(c, 32, 64, 0, 128) ?:
467 __test_extent_overwrite(c, 32, 64, 32, 64) ?:
468 __test_extent_overwrite(c, 32, 64, 32, 128);
469}
470
471static int insert_test_overlapping_extent(struct bch_fs *c, u64 inum, u64 start, u32 len, u32 snapid)
472{
473 struct bkey_i_cookie k;
474 int ret;
475
476 bkey_cookie_init(&k.k_i);
477 k.k_i.k.p.inode = inum;
478 k.k_i.k.p.offset = start + len;
479 k.k_i.k.p.snapshot = snapid;
480 k.k_i.k.size = len;
481
482 ret = bch2_trans_do(c, NULL, NULL, 0,
483 bch2_btree_insert_nonextent(trans, BTREE_ID_extents, &k.k_i,
484 BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE));
485 bch_err_fn(c, ret);
486 return ret;
487}
488
489static int test_extent_create_overlapping(struct bch_fs *c, u64 inum)
490{
491 return insert_test_overlapping_extent(c, inum, 0, 16, U32_MAX - 2) ?: /* overwrite entire */
492 insert_test_overlapping_extent(c, inum, 2, 8, U32_MAX - 2) ?:
493 insert_test_overlapping_extent(c, inum, 4, 4, U32_MAX) ?:
494 insert_test_overlapping_extent(c, inum, 32, 8, U32_MAX - 2) ?: /* overwrite front/back */
495 insert_test_overlapping_extent(c, inum, 36, 8, U32_MAX) ?:
496 insert_test_overlapping_extent(c, inum, 60, 8, U32_MAX - 2) ?:
497 insert_test_overlapping_extent(c, inum, 64, 8, U32_MAX);
498}
499
500/* snapshot unit tests */
501
502/* Test skipping over keys in unrelated snapshots: */
503static int test_snapshot_filter(struct bch_fs *c, u32 snapid_lo, u32 snapid_hi)
504{
505 struct btree_trans *trans;
506 struct btree_iter iter;
507 struct bkey_s_c k;
508 struct bkey_i_cookie cookie;
509 int ret;
510
511 bkey_cookie_init(&cookie.k_i);
512 cookie.k.p.snapshot = snapid_hi;
513 ret = bch2_btree_insert(c, BTREE_ID_xattrs, &cookie.k_i, NULL, 0);
514 if (ret)
515 return ret;
516
517 trans = bch2_trans_get(c);
518 bch2_trans_iter_init(trans, &iter, BTREE_ID_xattrs,
519 SPOS(0, 0, snapid_lo), 0);
520 lockrestart_do(trans, bkey_err(k = bch2_btree_iter_peek_upto(&iter, POS(0, U64_MAX))));
521
522 BUG_ON(k.k->p.snapshot != U32_MAX);
523
524 bch2_trans_iter_exit(trans, &iter);
525 bch2_trans_put(trans);
526 return ret;
527}
528
529static int test_snapshots(struct bch_fs *c, u64 nr)
530{
531 struct bkey_i_cookie cookie;
532 u32 snapids[2];
533 u32 snapid_subvols[2] = { 1, 1 };
534 int ret;
535
536 bkey_cookie_init(&cookie.k_i);
537 cookie.k.p.snapshot = U32_MAX;
538 ret = bch2_btree_insert(c, BTREE_ID_xattrs, &cookie.k_i, NULL, 0);
539 if (ret)
540 return ret;
541
542 ret = bch2_trans_do(c, NULL, NULL, 0,
543 bch2_snapshot_node_create(trans, U32_MAX,
544 snapids,
545 snapid_subvols,
546 2));
547 if (ret)
548 return ret;
549
550 if (snapids[0] > snapids[1])
551 swap(snapids[0], snapids[1]);
552
553 ret = test_snapshot_filter(c, snapids[0], snapids[1]);
554 bch_err_msg(c, ret, "from test_snapshot_filter");
555 return ret;
556}
557
558/* perf tests */
559
560static u64 test_rand(void)
561{
562 u64 v;
563
564 get_random_bytes(&v, sizeof(v));
565 return v;
566}
567
568static int rand_insert(struct bch_fs *c, u64 nr)
569{
570 struct btree_trans *trans = bch2_trans_get(c);
571 struct bkey_i_cookie k;
572 int ret = 0;
573 u64 i;
574
575 for (i = 0; i < nr; i++) {
576 bkey_cookie_init(&k.k_i);
577 k.k.p.offset = test_rand();
578 k.k.p.snapshot = U32_MAX;
579
580 ret = commit_do(trans, NULL, NULL, 0,
581 bch2_btree_insert_trans(trans, BTREE_ID_xattrs, &k.k_i, 0));
582 if (ret)
583 break;
584 }
585
586 bch2_trans_put(trans);
587 return ret;
588}
589
590static int rand_insert_multi(struct bch_fs *c, u64 nr)
591{
592 struct btree_trans *trans = bch2_trans_get(c);
593 struct bkey_i_cookie k[8];
594 int ret = 0;
595 unsigned j;
596 u64 i;
597
598 for (i = 0; i < nr; i += ARRAY_SIZE(k)) {
599 for (j = 0; j < ARRAY_SIZE(k); j++) {
600 bkey_cookie_init(&k[j].k_i);
601 k[j].k.p.offset = test_rand();
602 k[j].k.p.snapshot = U32_MAX;
603 }
604
605 ret = commit_do(trans, NULL, NULL, 0,
606 bch2_btree_insert_trans(trans, BTREE_ID_xattrs, &k[0].k_i, 0) ?:
607 bch2_btree_insert_trans(trans, BTREE_ID_xattrs, &k[1].k_i, 0) ?:
608 bch2_btree_insert_trans(trans, BTREE_ID_xattrs, &k[2].k_i, 0) ?:
609 bch2_btree_insert_trans(trans, BTREE_ID_xattrs, &k[3].k_i, 0) ?:
610 bch2_btree_insert_trans(trans, BTREE_ID_xattrs, &k[4].k_i, 0) ?:
611 bch2_btree_insert_trans(trans, BTREE_ID_xattrs, &k[5].k_i, 0) ?:
612 bch2_btree_insert_trans(trans, BTREE_ID_xattrs, &k[6].k_i, 0) ?:
613 bch2_btree_insert_trans(trans, BTREE_ID_xattrs, &k[7].k_i, 0));
614 if (ret)
615 break;
616 }
617
618 bch2_trans_put(trans);
619 return ret;
620}
621
622static int rand_lookup(struct bch_fs *c, u64 nr)
623{
624 struct btree_trans *trans = bch2_trans_get(c);
625 struct btree_iter iter;
626 struct bkey_s_c k;
627 int ret = 0;
628 u64 i;
629
630 bch2_trans_iter_init(trans, &iter, BTREE_ID_xattrs,
631 SPOS(0, 0, U32_MAX), 0);
632
633 for (i = 0; i < nr; i++) {
634 bch2_btree_iter_set_pos(&iter, SPOS(0, test_rand(), U32_MAX));
635
636 lockrestart_do(trans, bkey_err(k = bch2_btree_iter_peek(&iter)));
637 ret = bkey_err(k);
638 if (ret)
639 break;
640 }
641
642 bch2_trans_iter_exit(trans, &iter);
643 bch2_trans_put(trans);
644 return ret;
645}
646
647static int rand_mixed_trans(struct btree_trans *trans,
648 struct btree_iter *iter,
649 struct bkey_i_cookie *cookie,
650 u64 i, u64 pos)
651{
652 struct bkey_s_c k;
653 int ret;
654
655 bch2_btree_iter_set_pos(iter, SPOS(0, pos, U32_MAX));
656
657 k = bch2_btree_iter_peek(iter);
658 ret = bkey_err(k);
659 bch_err_msg(trans->c, ret, "lookup error");
660 if (ret)
661 return ret;
662
663 if (!(i & 3) && k.k) {
664 bkey_cookie_init(&cookie->k_i);
665 cookie->k.p = iter->pos;
666 ret = bch2_trans_update(trans, iter, &cookie->k_i, 0);
667 }
668
669 return ret;
670}
671
672static int rand_mixed(struct bch_fs *c, u64 nr)
673{
674 struct btree_trans *trans = bch2_trans_get(c);
675 struct btree_iter iter;
676 struct bkey_i_cookie cookie;
677 int ret = 0;
678 u64 i, rand;
679
680 bch2_trans_iter_init(trans, &iter, BTREE_ID_xattrs,
681 SPOS(0, 0, U32_MAX), 0);
682
683 for (i = 0; i < nr; i++) {
684 rand = test_rand();
685 ret = commit_do(trans, NULL, NULL, 0,
686 rand_mixed_trans(trans, &iter, &cookie, i, rand));
687 if (ret)
688 break;
689 }
690
691 bch2_trans_iter_exit(trans, &iter);
692 bch2_trans_put(trans);
693 return ret;
694}
695
696static int __do_delete(struct btree_trans *trans, struct bpos pos)
697{
698 struct btree_iter iter;
699 struct bkey_s_c k;
700 int ret = 0;
701
702 bch2_trans_iter_init(trans, &iter, BTREE_ID_xattrs, pos,
703 BTREE_ITER_INTENT);
704 k = bch2_btree_iter_peek(&iter);
705 ret = bkey_err(k);
706 if (ret)
707 goto err;
708
709 if (!k.k)
710 goto err;
711
712 ret = bch2_btree_delete_at(trans, &iter, 0);
713err:
714 bch2_trans_iter_exit(trans, &iter);
715 return ret;
716}
717
718static int rand_delete(struct bch_fs *c, u64 nr)
719{
720 struct btree_trans *trans = bch2_trans_get(c);
721 int ret = 0;
722 u64 i;
723
724 for (i = 0; i < nr; i++) {
725 struct bpos pos = SPOS(0, test_rand(), U32_MAX);
726
727 ret = commit_do(trans, NULL, NULL, 0,
728 __do_delete(trans, pos));
729 if (ret)
730 break;
731 }
732
733 bch2_trans_put(trans);
734 return ret;
735}
736
737static int seq_insert(struct bch_fs *c, u64 nr)
738{
739 struct btree_iter iter;
740 struct bkey_s_c k;
741 struct bkey_i_cookie insert;
742
743 bkey_cookie_init(&insert.k_i);
744
745 return bch2_trans_run(c,
746 for_each_btree_key_commit(trans, iter, BTREE_ID_xattrs,
747 SPOS(0, 0, U32_MAX),
748 BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k,
749 NULL, NULL, 0, ({
750 if (iter.pos.offset >= nr)
751 break;
752 insert.k.p = iter.pos;
753 bch2_trans_update(trans, &iter, &insert.k_i, 0);
754 })));
755}
756
757static int seq_lookup(struct bch_fs *c, u64 nr)
758{
759 struct btree_iter iter;
760 struct bkey_s_c k;
761
762 return bch2_trans_run(c,
763 for_each_btree_key2_upto(trans, iter, BTREE_ID_xattrs,
764 SPOS(0, 0, U32_MAX), POS(0, U64_MAX),
765 0, k,
766 0));
767}
768
769static int seq_overwrite(struct bch_fs *c, u64 nr)
770{
771 struct btree_iter iter;
772 struct bkey_s_c k;
773
774 return bch2_trans_run(c,
775 for_each_btree_key_commit(trans, iter, BTREE_ID_xattrs,
776 SPOS(0, 0, U32_MAX),
777 BTREE_ITER_INTENT, k,
778 NULL, NULL, 0, ({
779 struct bkey_i_cookie u;
780
781 bkey_reassemble(&u.k_i, k);
782 bch2_trans_update(trans, &iter, &u.k_i, 0);
783 })));
784}
785
786static int seq_delete(struct bch_fs *c, u64 nr)
787{
788 return bch2_btree_delete_range(c, BTREE_ID_xattrs,
789 SPOS(0, 0, U32_MAX),
790 POS(0, U64_MAX),
791 0, NULL);
792}
793
794typedef int (*perf_test_fn)(struct bch_fs *, u64);
795
796struct test_job {
797 struct bch_fs *c;
798 u64 nr;
799 unsigned nr_threads;
800 perf_test_fn fn;
801
802 atomic_t ready;
803 wait_queue_head_t ready_wait;
804
805 atomic_t done;
806 struct completion done_completion;
807
808 u64 start;
809 u64 finish;
810 int ret;
811};
812
813static int btree_perf_test_thread(void *data)
814{
815 struct test_job *j = data;
816 int ret;
817
818 if (atomic_dec_and_test(&j->ready)) {
819 wake_up(&j->ready_wait);
820 j->start = sched_clock();
821 } else {
822 wait_event(j->ready_wait, !atomic_read(&j->ready));
823 }
824
825 ret = j->fn(j->c, div64_u64(j->nr, j->nr_threads));
826 if (ret) {
827 bch_err(j->c, "%ps: error %s", j->fn, bch2_err_str(ret));
828 j->ret = ret;
829 }
830
831 if (atomic_dec_and_test(&j->done)) {
832 j->finish = sched_clock();
833 complete(&j->done_completion);
834 }
835
836 return 0;
837}
838
839int bch2_btree_perf_test(struct bch_fs *c, const char *testname,
840 u64 nr, unsigned nr_threads)
841{
842 struct test_job j = { .c = c, .nr = nr, .nr_threads = nr_threads };
843 char name_buf[20];
844 struct printbuf nr_buf = PRINTBUF;
845 struct printbuf per_sec_buf = PRINTBUF;
846 unsigned i;
847 u64 time;
848
849 atomic_set(&j.ready, nr_threads);
850 init_waitqueue_head(&j.ready_wait);
851
852 atomic_set(&j.done, nr_threads);
853 init_completion(&j.done_completion);
854
855#define perf_test(_test) \
856 if (!strcmp(testname, #_test)) j.fn = _test
857
858 perf_test(rand_insert);
859 perf_test(rand_insert_multi);
860 perf_test(rand_lookup);
861 perf_test(rand_mixed);
862 perf_test(rand_delete);
863
864 perf_test(seq_insert);
865 perf_test(seq_lookup);
866 perf_test(seq_overwrite);
867 perf_test(seq_delete);
868
869 /* a unit test, not a perf test: */
870 perf_test(test_delete);
871 perf_test(test_delete_written);
872 perf_test(test_iterate);
873 perf_test(test_iterate_extents);
874 perf_test(test_iterate_slots);
875 perf_test(test_iterate_slots_extents);
876 perf_test(test_peek_end);
877 perf_test(test_peek_end_extents);
878
879 perf_test(test_extent_overwrite_front);
880 perf_test(test_extent_overwrite_back);
881 perf_test(test_extent_overwrite_middle);
882 perf_test(test_extent_overwrite_all);
883 perf_test(test_extent_create_overlapping);
884
885 perf_test(test_snapshots);
886
887 if (!j.fn) {
888 pr_err("unknown test %s", testname);
889 return -EINVAL;
890 }
891
892 //pr_info("running test %s:", testname);
893
894 if (nr_threads == 1)
895 btree_perf_test_thread(&j);
896 else
897 for (i = 0; i < nr_threads; i++)
898 kthread_run(btree_perf_test_thread, &j,
899 "bcachefs perf test[%u]", i);
900
901 while (wait_for_completion_interruptible(&j.done_completion))
902 ;
903
904 time = j.finish - j.start;
905
906 scnprintf(name_buf, sizeof(name_buf), "%s:", testname);
907 prt_human_readable_u64(&nr_buf, nr);
908 prt_human_readable_u64(&per_sec_buf, div64_u64(nr * NSEC_PER_SEC, time));
909 printk(KERN_INFO "%-12s %s with %u threads in %5llu sec, %5llu nsec per iter, %5s per sec\n",
910 name_buf, nr_buf.buf, nr_threads,
911 div_u64(time, NSEC_PER_SEC),
912 div_u64(time * nr_threads, nr),
913 per_sec_buf.buf);
914 printbuf_exit(&per_sec_buf);
915 printbuf_exit(&nr_buf);
916 return j.ret;
917}
918
919#endif /* CONFIG_BCACHEFS_TESTS */