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