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