]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/processor-trace/libipt/test/src/ptunit-image_section_cache.c
Merge ^/vendor/lvm-project/release-10.x up to its last change (upstream
[FreeBSD/FreeBSD.git] / contrib / processor-trace / libipt / test / src / ptunit-image_section_cache.c
1 /*
2  * Copyright (c) 2016-2019, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  * Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright notice,
10  *    this list of conditions and the following disclaimer in the documentation
11  *    and/or other materials provided with the distribution.
12  *  * Neither the name of Intel Corporation nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "pt_image_section_cache.h"
30
31 #include "ptunit_threads.h"
32
33 #include "intel-pt.h"
34
35 #include <stdlib.h>
36
37
38 struct pt_section {
39         /* The filename.  We only support string literals for testing. */
40         const char *filename;
41
42         /* The file offset and size. */
43         uint64_t offset;
44         uint64_t size;
45
46         /* The bcache size. */
47         uint64_t bcsize;
48
49         /* The iscache back link. */
50         struct pt_image_section_cache *iscache;
51
52         /* The file content. */
53         uint8_t content[0x10];
54
55         /* The use count. */
56         int ucount;
57
58         /* The attach count. */
59         int acount;
60
61         /* The map count. */
62         int mcount;
63
64 #if defined(FEATURE_THREADS)
65         /* A lock protecting this section. */
66         mtx_t lock;
67         /* A lock protecting the iscache and acount fields. */
68         mtx_t alock;
69 #endif /* defined(FEATURE_THREADS) */
70 };
71
72 extern int pt_mk_section(struct pt_section **psection, const char *filename,
73                          uint64_t offset, uint64_t size);
74
75 extern int pt_section_get(struct pt_section *section);
76 extern int pt_section_put(struct pt_section *section);
77 extern int pt_section_attach(struct pt_section *section,
78                              struct pt_image_section_cache *iscache);
79 extern int pt_section_detach(struct pt_section *section,
80                              struct pt_image_section_cache *iscache);
81
82 extern int pt_section_map(struct pt_section *section);
83 extern int pt_section_map_share(struct pt_section *section);
84 extern int pt_section_unmap(struct pt_section *section);
85 extern int pt_section_request_bcache(struct pt_section *section);
86
87 extern const char *pt_section_filename(const struct pt_section *section);
88 extern uint64_t pt_section_offset(const struct pt_section *section);
89 extern uint64_t pt_section_size(const struct pt_section *section);
90 extern int pt_section_memsize(struct pt_section *section, uint64_t *size);
91
92 extern int pt_section_read(const struct pt_section *section, uint8_t *buffer,
93                            uint16_t size, uint64_t offset);
94
95
96 int pt_mk_section(struct pt_section **psection, const char *filename,
97                   uint64_t offset, uint64_t size)
98 {
99         struct pt_section *section;
100         uint8_t idx;
101
102         section = malloc(sizeof(*section));
103         if (!section)
104                 return -pte_nomem;
105
106         memset(section, 0, sizeof(*section));
107         section->filename = filename;
108         section->offset = offset;
109         section->size = size;
110         section->ucount = 1;
111
112         for (idx = 0; idx < sizeof(section->content); ++idx)
113                 section->content[idx] = idx;
114
115 #if defined(FEATURE_THREADS)
116         {
117                 int errcode;
118
119                 errcode = mtx_init(&section->lock, mtx_plain);
120                 if (errcode != thrd_success) {
121                         free(section);
122                         return -pte_bad_lock;
123                 }
124
125                 errcode = mtx_init(&section->alock, mtx_plain);
126                 if (errcode != thrd_success) {
127                         mtx_destroy(&section->lock);
128                         free(section);
129                         return -pte_bad_lock;
130                 }
131         }
132 #endif /* defined(FEATURE_THREADS) */
133
134         *psection = section;
135
136         return 0;
137 }
138
139 static int pt_section_lock(struct pt_section *section)
140 {
141         if (!section)
142                 return -pte_internal;
143
144 #if defined(FEATURE_THREADS)
145         {
146                 int errcode;
147
148                 errcode = mtx_lock(&section->lock);
149                 if (errcode != thrd_success)
150                         return -pte_bad_lock;
151         }
152 #endif /* defined(FEATURE_THREADS) */
153
154         return 0;
155 }
156
157 static int pt_section_unlock(struct pt_section *section)
158 {
159         if (!section)
160                 return -pte_internal;
161
162 #if defined(FEATURE_THREADS)
163         {
164                 int errcode;
165
166                 errcode = mtx_unlock(&section->lock);
167                 if (errcode != thrd_success)
168                         return -pte_bad_lock;
169         }
170 #endif /* defined(FEATURE_THREADS) */
171
172         return 0;
173 }
174
175 static int pt_section_lock_attach(struct pt_section *section)
176 {
177         if (!section)
178                 return -pte_internal;
179
180 #if defined(FEATURE_THREADS)
181         {
182                 int errcode;
183
184                 errcode = mtx_lock(&section->alock);
185                 if (errcode != thrd_success)
186                         return -pte_bad_lock;
187         }
188 #endif /* defined(FEATURE_THREADS) */
189
190         return 0;
191 }
192
193 static int pt_section_unlock_attach(struct pt_section *section)
194 {
195         if (!section)
196                 return -pte_internal;
197
198 #if defined(FEATURE_THREADS)
199         {
200                 int errcode;
201
202                 errcode = mtx_unlock(&section->alock);
203                 if (errcode != thrd_success)
204                         return -pte_bad_lock;
205         }
206 #endif /* defined(FEATURE_THREADS) */
207
208         return 0;
209 }
210
211 int pt_section_get(struct pt_section *section)
212 {
213         int errcode, ucount;
214
215         if (!section)
216                 return -pte_internal;
217
218         errcode = pt_section_lock(section);
219         if (errcode < 0)
220                 return errcode;
221
222         ucount = ++section->ucount;
223
224         errcode = pt_section_unlock(section);
225         if (errcode < 0)
226                 return errcode;
227
228         if (!ucount)
229                 return -pte_internal;
230
231         return 0;
232 }
233
234 int pt_section_put(struct pt_section *section)
235 {
236         int errcode, ucount;
237
238         if (!section)
239                 return -pte_internal;
240
241         errcode = pt_section_lock(section);
242         if (errcode < 0)
243                 return errcode;
244
245         ucount = --section->ucount;
246
247         errcode = pt_section_unlock(section);
248         if (errcode < 0)
249                 return errcode;
250
251         if (!ucount) {
252 #if defined(FEATURE_THREADS)
253                 mtx_destroy(&section->alock);
254                 mtx_destroy(&section->lock);
255 #endif /* defined(FEATURE_THREADS) */
256                 free(section);
257         }
258
259         return 0;
260 }
261
262 int pt_section_attach(struct pt_section *section,
263                       struct pt_image_section_cache *iscache)
264 {
265         int errcode, ucount, acount;
266
267         if (!section || !iscache)
268                 return -pte_internal;
269
270         errcode = pt_section_lock_attach(section);
271         if (errcode < 0)
272                 return errcode;
273
274         ucount = section->ucount;
275         acount = section->acount;
276         if (!acount) {
277                 if (section->iscache || !ucount)
278                         goto out_unlock;
279
280                 section->iscache = iscache;
281                 section->acount = 1;
282
283                 return pt_section_unlock_attach(section);
284         }
285
286         acount += 1;
287         if (!acount) {
288                 (void) pt_section_unlock_attach(section);
289                 return -pte_overflow;
290         }
291
292         if (ucount < acount)
293                 goto out_unlock;
294
295         if (section->iscache != iscache)
296                 goto out_unlock;
297
298         section->acount = acount;
299
300         return pt_section_unlock_attach(section);
301
302  out_unlock:
303         (void) pt_section_unlock_attach(section);
304         return -pte_internal;
305 }
306
307 int pt_section_detach(struct pt_section *section,
308                       struct pt_image_section_cache *iscache)
309 {
310         int errcode, ucount, acount;
311
312         if (!section || !iscache)
313                 return -pte_internal;
314
315         errcode = pt_section_lock_attach(section);
316         if (errcode < 0)
317                 return errcode;
318
319         if (section->iscache != iscache)
320                 goto out_unlock;
321
322         acount = section->acount;
323         if (!acount)
324                 goto out_unlock;
325
326         acount -= 1;
327         ucount = section->ucount;
328         if (ucount < acount)
329                 goto out_unlock;
330
331         section->acount = acount;
332         if (!acount)
333                 section->iscache = NULL;
334
335         return pt_section_unlock_attach(section);
336
337  out_unlock:
338         (void) pt_section_unlock_attach(section);
339         return -pte_internal;
340 }
341
342 int pt_section_map(struct pt_section *section)
343 {
344         struct pt_image_section_cache *iscache;
345         int errcode, status;
346
347         if (!section)
348                 return -pte_internal;
349
350         errcode = pt_section_map_share(section);
351         if (errcode < 0)
352                 return errcode;
353
354         errcode = pt_section_lock_attach(section);
355         if (errcode < 0)
356                 return errcode;
357
358         status = 0;
359         iscache = section->iscache;
360         if (iscache)
361                 status = pt_iscache_notify_map(iscache, section);
362
363         errcode = pt_section_unlock_attach(section);
364
365         return (status < 0) ? status : errcode;
366 }
367
368 int pt_section_map_share(struct pt_section *section)
369 {
370         int errcode, mcount;
371
372         if (!section)
373                 return -pte_internal;
374
375         errcode = pt_section_lock(section);
376         if (errcode < 0)
377                 return errcode;
378
379         mcount = ++section->mcount;
380
381         errcode = pt_section_unlock(section);
382         if (errcode < 0)
383                 return errcode;
384
385         if (mcount <= 0)
386                 return -pte_internal;
387
388         return 0;
389 }
390
391 int pt_section_unmap(struct pt_section *section)
392 {
393         int errcode, mcount;
394
395         if (!section)
396                 return -pte_internal;
397
398         errcode = pt_section_lock(section);
399         if (errcode < 0)
400                 return errcode;
401
402         section->bcsize = 0ull;
403         mcount = --section->mcount;
404
405         errcode = pt_section_unlock(section);
406         if (errcode < 0)
407                 return errcode;
408
409         if (mcount < 0)
410                 return -pte_internal;
411
412         return 0;
413 }
414
415 int pt_section_request_bcache(struct pt_section *section)
416 {
417         struct pt_image_section_cache *iscache;
418         uint64_t memsize;
419         int errcode;
420
421         if (!section)
422                 return -pte_internal;
423
424         errcode = pt_section_lock_attach(section);
425         if (errcode < 0)
426                 return errcode;
427
428         errcode = pt_section_lock(section);
429         if (errcode < 0)
430                 goto out_alock;
431
432         if (section->bcsize)
433                 goto out_lock;
434
435         section->bcsize = section->size * 3;
436         memsize = section->size + section->bcsize;
437
438         errcode = pt_section_unlock(section);
439         if (errcode < 0)
440                 goto out_alock;
441
442         iscache = section->iscache;
443         if (iscache) {
444                 errcode = pt_iscache_notify_resize(iscache, section, memsize);
445                 if (errcode < 0)
446                         goto out_alock;
447         }
448
449         return pt_section_unlock_attach(section);
450
451
452 out_lock:
453         (void) pt_section_unlock(section);
454
455 out_alock:
456         (void) pt_section_unlock_attach(section);
457         return errcode;
458 }
459
460 const char *pt_section_filename(const struct pt_section *section)
461 {
462         if (!section)
463                 return NULL;
464
465         return section->filename;
466 }
467
468 uint64_t pt_section_offset(const struct pt_section *section)
469 {
470         if (!section)
471                 return 0ull;
472
473         return section->offset;
474 }
475
476 uint64_t pt_section_size(const struct pt_section *section)
477 {
478         if (!section)
479                 return 0ull;
480
481         return section->size;
482 }
483
484 int pt_section_memsize(struct pt_section *section, uint64_t *size)
485 {
486         if (!section || !size)
487                 return -pte_internal;
488
489         *size = section->mcount ? section->size + section->bcsize : 0ull;
490
491         return 0;
492 }
493
494 int pt_section_read(const struct pt_section *section, uint8_t *buffer,
495                     uint16_t size, uint64_t offset)
496 {
497         uint64_t begin, end, max;
498
499         if (!section || !buffer)
500                 return -pte_internal;
501
502         begin = offset;
503         end = begin + size;
504         max = sizeof(section->content);
505
506         if (max <= begin)
507                 return -pte_nomap;
508
509         if (max < end)
510                 end = max;
511
512         if (end <= begin)
513                 return -pte_invalid;
514
515         memcpy(buffer, &section->content[begin], (size_t) (end - begin));
516         return (int) (end - begin);
517 }
518
519 enum {
520         /* The number of test sections. */
521         num_sections    = 8,
522
523 #if defined(FEATURE_THREADS)
524
525         num_threads     = 8,
526
527 #endif /* defined(FEATURE_THREADS) */
528
529         num_iterations  = 0x1000
530 };
531
532 struct iscache_fixture {
533         /* Threading support. */
534         struct ptunit_thrd_fixture thrd;
535
536         /* The image section cache under test. */
537         struct pt_image_section_cache iscache;
538
539         /* A bunch of test sections. */
540         struct pt_section *section[num_sections];
541
542         /* The test fixture initialization and finalization functions. */
543         struct ptunit_result (*init)(struct iscache_fixture *);
544         struct ptunit_result (*fini)(struct iscache_fixture *);
545 };
546
547 static struct ptunit_result dfix_init(struct iscache_fixture *cfix)
548 {
549         int idx;
550
551         ptu_test(ptunit_thrd_init, &cfix->thrd);
552
553         memset(cfix->section, 0, sizeof(cfix->section));
554
555         for (idx = 0; idx < num_sections; ++idx) {
556                 struct pt_section *section;
557                 int errcode;
558
559                 errcode = pt_mk_section(&section, "some-filename",
560                                         idx % 3 == 0 ? 0x1000 : 0x2000,
561                                         idx % 2 == 0 ? 0x1000 : 0x2000);
562                 ptu_int_eq(errcode, 0);
563                 ptu_ptr(section);
564
565                 cfix->section[idx] = section;
566         }
567
568         return ptu_passed();
569 }
570
571 static struct ptunit_result cfix_init(struct iscache_fixture *cfix)
572 {
573         int errcode;
574
575         ptu_test(dfix_init, cfix);
576
577         errcode = pt_iscache_init(&cfix->iscache, NULL);
578         ptu_int_eq(errcode, 0);
579
580         return ptu_passed();
581 }
582
583 static struct ptunit_result sfix_init(struct iscache_fixture *cfix)
584 {
585         int status, idx;
586
587         ptu_test(cfix_init, cfix);
588
589         cfix->iscache.limit = 0x7800;
590
591         for (idx = 0; idx < num_sections; ++idx) {
592                 status = pt_iscache_add(&cfix->iscache, cfix->section[idx],
593                                         0ull);
594                 ptu_int_ge(status, 0);
595         }
596
597         return ptu_passed();
598 }
599
600 static struct ptunit_result cfix_fini(struct iscache_fixture *cfix)
601 {
602         int idx, errcode;
603
604         ptu_test(ptunit_thrd_fini, &cfix->thrd);
605
606         for (idx = 0; idx < cfix->thrd.nthreads; ++idx)
607                 ptu_int_eq(cfix->thrd.result[idx], 0);
608
609         pt_iscache_fini(&cfix->iscache);
610
611         for (idx = 0; idx < num_sections; ++idx) {
612                 ptu_int_eq(cfix->section[idx]->ucount, 1);
613                 ptu_int_eq(cfix->section[idx]->acount, 0);
614                 ptu_int_eq(cfix->section[idx]->mcount, 0);
615                 ptu_null(cfix->section[idx]->iscache);
616
617                 errcode = pt_section_put(cfix->section[idx]);
618                 ptu_int_eq(errcode, 0);
619         }
620
621         return ptu_passed();
622 }
623
624
625 static struct ptunit_result init_null(void)
626 {
627         int errcode;
628
629         errcode = pt_iscache_init(NULL, NULL);
630         ptu_int_eq(errcode, -pte_internal);
631
632         return ptu_passed();
633 }
634
635 static struct ptunit_result fini_null(void)
636 {
637         pt_iscache_fini(NULL);
638
639         return ptu_passed();
640 }
641
642 static struct ptunit_result name_null(void)
643 {
644         const char *name;
645
646         name = pt_iscache_name(NULL);
647         ptu_null(name);
648
649         return ptu_passed();
650 }
651
652 static struct ptunit_result add_null(void)
653 {
654         struct pt_image_section_cache iscache;
655         struct pt_section section;
656         int errcode;
657
658         errcode = pt_iscache_add(NULL, &section, 0ull);
659         ptu_int_eq(errcode, -pte_internal);
660
661         errcode = pt_iscache_add(&iscache, NULL, 0ull);
662         ptu_int_eq(errcode, -pte_internal);
663
664         return ptu_passed();
665 }
666
667 static struct ptunit_result find_null(void)
668 {
669         int errcode;
670
671         errcode = pt_iscache_find(NULL, "filename", 0ull, 0ull, 0ull);
672         ptu_int_eq(errcode, -pte_internal);
673
674         return ptu_passed();
675 }
676
677 static struct ptunit_result lookup_null(void)
678 {
679         struct pt_image_section_cache iscache;
680         struct pt_section *section;
681         uint64_t laddr;
682         int errcode;
683
684         errcode = pt_iscache_lookup(NULL, &section, &laddr, 0);
685         ptu_int_eq(errcode, -pte_internal);
686
687         errcode = pt_iscache_lookup(&iscache, NULL, &laddr, 0);
688         ptu_int_eq(errcode, -pte_internal);
689
690         errcode = pt_iscache_lookup(&iscache, &section, NULL, 0);
691         ptu_int_eq(errcode, -pte_internal);
692
693         return ptu_passed();
694 }
695
696 static struct ptunit_result clear_null(void)
697 {
698         int errcode;
699
700         errcode = pt_iscache_clear(NULL);
701         ptu_int_eq(errcode, -pte_internal);
702
703         return ptu_passed();
704 }
705
706 static struct ptunit_result free_null(void)
707 {
708         pt_iscache_free(NULL);
709
710         return ptu_passed();
711 }
712
713 static struct ptunit_result add_file_null(void)
714 {
715         struct pt_image_section_cache iscache;
716         int errcode;
717
718         errcode = pt_iscache_add_file(NULL, "filename", 0ull, 0ull, 0ull);
719         ptu_int_eq(errcode, -pte_invalid);
720
721         errcode = pt_iscache_add_file(&iscache, NULL, 0ull, 0ull, 0ull);
722         ptu_int_eq(errcode, -pte_invalid);
723
724         return ptu_passed();
725 }
726
727 static struct ptunit_result read_null(void)
728 {
729         struct pt_image_section_cache iscache;
730         uint8_t buffer;
731         int errcode;
732
733         errcode = pt_iscache_read(NULL, &buffer, sizeof(buffer), 1ull, 0ull);
734         ptu_int_eq(errcode, -pte_invalid);
735
736         errcode = pt_iscache_read(&iscache, NULL, sizeof(buffer), 1ull, 0ull);
737         ptu_int_eq(errcode, -pte_invalid);
738
739         errcode = pt_iscache_read(&iscache, &buffer, 0ull, 1, 0ull);
740         ptu_int_eq(errcode, -pte_invalid);
741
742         return ptu_passed();
743 }
744
745 static struct ptunit_result init_fini(struct iscache_fixture *cfix)
746 {
747         (void) cfix;
748
749         /* The actual init and fini calls are in cfix_init() and cfix_fini(). */
750         return ptu_passed();
751 }
752
753 static struct ptunit_result name(struct iscache_fixture *cfix)
754 {
755         const char *name;
756
757         pt_iscache_init(&cfix->iscache, "iscache-name");
758
759         name = pt_iscache_name(&cfix->iscache);
760         ptu_str_eq(name, "iscache-name");
761
762         return ptu_passed();
763 }
764
765 static struct ptunit_result name_none(struct iscache_fixture *cfix)
766 {
767         const char *name;
768
769         pt_iscache_init(&cfix->iscache, NULL);
770
771         name = pt_iscache_name(&cfix->iscache);
772         ptu_null(name);
773
774         return ptu_passed();
775 }
776
777 static struct ptunit_result add(struct iscache_fixture *cfix)
778 {
779         int isid;
780
781         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
782         ptu_int_gt(isid, 0);
783
784         /* The cache attaches and gets a reference on success. */
785         ptu_int_eq(cfix->section[0]->ucount, 2);
786         ptu_int_eq(cfix->section[0]->acount, 1);
787
788         /* The added section must be implicitly put in pt_iscache_fini. */
789         return ptu_passed();
790 }
791
792 static struct ptunit_result add_no_name(struct iscache_fixture *cfix)
793 {
794         struct pt_section section;
795         int errcode;
796
797         memset(&section, 0, sizeof(section));
798
799         errcode = pt_iscache_add(&cfix->iscache, &section, 0ull);
800         ptu_int_eq(errcode, -pte_internal);
801
802         return ptu_passed();
803 }
804
805 static struct ptunit_result add_file(struct iscache_fixture *cfix)
806 {
807         int isid;
808
809         isid = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull);
810         ptu_int_gt(isid, 0);
811
812         return ptu_passed();
813 }
814
815 static struct ptunit_result find(struct iscache_fixture *cfix)
816 {
817         struct pt_section *section;
818         int found, isid;
819
820         section = cfix->section[0];
821         ptu_ptr(section);
822
823         isid = pt_iscache_add(&cfix->iscache, section, 0ull);
824         ptu_int_gt(isid, 0);
825
826         found = pt_iscache_find(&cfix->iscache, section->filename,
827                                 section->offset, section->size, 0ull);
828         ptu_int_eq(found, isid);
829
830         return ptu_passed();
831 }
832
833 static struct ptunit_result find_empty(struct iscache_fixture *cfix)
834 {
835         struct pt_section *section;
836         int found;
837
838         section = cfix->section[0];
839         ptu_ptr(section);
840
841         found = pt_iscache_find(&cfix->iscache, section->filename,
842                                 section->offset, section->size, 0ull);
843         ptu_int_eq(found, 0);
844
845         return ptu_passed();
846 }
847
848 static struct ptunit_result find_bad_filename(struct iscache_fixture *cfix)
849 {
850         struct pt_section *section;
851         int found, isid;
852
853         section = cfix->section[0];
854         ptu_ptr(section);
855
856         isid = pt_iscache_add(&cfix->iscache, section, 0ull);
857         ptu_int_gt(isid, 0);
858
859         found = pt_iscache_find(&cfix->iscache, "bad-filename",
860                                 section->offset, section->size, 0ull);
861         ptu_int_eq(found, 0);
862
863         return ptu_passed();
864 }
865
866 static struct ptunit_result find_null_filename(struct iscache_fixture *cfix)
867 {
868         int errcode;
869
870         errcode = pt_iscache_find(&cfix->iscache, NULL, 0ull, 0ull, 0ull);
871         ptu_int_eq(errcode, -pte_internal);
872
873         return ptu_passed();
874 }
875
876 static struct ptunit_result find_bad_offset(struct iscache_fixture *cfix)
877 {
878         struct pt_section *section;
879         int found, isid;
880
881         section = cfix->section[0];
882         ptu_ptr(section);
883
884         isid = pt_iscache_add(&cfix->iscache, section, 0ull);
885         ptu_int_gt(isid, 0);
886
887         found = pt_iscache_find(&cfix->iscache, section->filename, 0ull,
888                                 section->size, 0ull);
889         ptu_int_eq(found, 0);
890
891         return ptu_passed();
892 }
893
894 static struct ptunit_result find_bad_size(struct iscache_fixture *cfix)
895 {
896         struct pt_section *section;
897         int found, isid;
898
899         section = cfix->section[0];
900         ptu_ptr(section);
901
902         isid = pt_iscache_add(&cfix->iscache, section, 0ull);
903         ptu_int_gt(isid, 0);
904
905         found = pt_iscache_find(&cfix->iscache, section->filename,
906                                 section->offset, 0ull, 0ull);
907         ptu_int_eq(found, 0);
908
909         return ptu_passed();
910 }
911
912 static struct ptunit_result find_bad_laddr(struct iscache_fixture *cfix)
913 {
914         struct pt_section *section;
915         int found, isid;
916
917         section = cfix->section[0];
918         ptu_ptr(section);
919
920         isid = pt_iscache_add(&cfix->iscache, section, 0ull);
921         ptu_int_gt(isid, 0);
922
923         found = pt_iscache_find(&cfix->iscache, section->filename,
924                                 section->offset, section->size, 1ull);
925         ptu_int_eq(found, 0);
926
927         return ptu_passed();
928 }
929
930 static struct ptunit_result lookup(struct iscache_fixture *cfix)
931 {
932         struct pt_section *section;
933         uint64_t laddr;
934         int errcode, isid;
935
936         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
937         ptu_int_gt(isid, 0);
938
939         errcode = pt_iscache_lookup(&cfix->iscache, &section, &laddr, isid);
940         ptu_int_eq(errcode, 0);
941         ptu_ptr_eq(section, cfix->section[0]);
942         ptu_uint_eq(laddr, 0ull);
943
944         errcode = pt_section_put(section);
945         ptu_int_eq(errcode, 0);
946
947         return ptu_passed();
948 }
949
950 static struct ptunit_result lookup_bad_isid(struct iscache_fixture *cfix)
951 {
952         struct pt_section *section;
953         uint64_t laddr;
954         int errcode, isid;
955
956         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
957         ptu_int_gt(isid, 0);
958
959         errcode = pt_iscache_lookup(&cfix->iscache, &section, &laddr, 0);
960         ptu_int_eq(errcode, -pte_bad_image);
961
962         errcode = pt_iscache_lookup(&cfix->iscache, &section, &laddr, -isid);
963         ptu_int_eq(errcode, -pte_bad_image);
964
965         errcode = pt_iscache_lookup(&cfix->iscache, &section, &laddr, isid + 1);
966         ptu_int_eq(errcode, -pte_bad_image);
967
968         return ptu_passed();
969 }
970
971 static struct ptunit_result clear_empty(struct iscache_fixture *cfix)
972 {
973         int errcode;
974
975         errcode = pt_iscache_clear(&cfix->iscache);
976         ptu_int_eq(errcode, 0);
977
978         return ptu_passed();
979 }
980
981 static struct ptunit_result clear_find(struct iscache_fixture *cfix)
982 {
983         struct pt_section *section;
984         int errcode, found, isid;
985
986         section = cfix->section[0];
987         ptu_ptr(section);
988
989         isid = pt_iscache_add(&cfix->iscache, section, 0ull);
990         ptu_int_gt(isid, 0);
991
992         errcode = pt_iscache_clear(&cfix->iscache);
993         ptu_int_eq(errcode, 0);
994
995
996         found = pt_iscache_find(&cfix->iscache, section->filename,
997                                 section->offset, section->size, 0ull);
998         ptu_int_eq(found, 0);
999
1000         return ptu_passed();
1001 }
1002
1003 static struct ptunit_result clear_lookup(struct iscache_fixture *cfix)
1004 {
1005         struct pt_section *section;
1006         uint64_t laddr;
1007         int errcode, isid;
1008
1009         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1010         ptu_int_gt(isid, 0);
1011
1012         errcode = pt_iscache_clear(&cfix->iscache);
1013         ptu_int_eq(errcode, 0);
1014
1015         errcode = pt_iscache_lookup(&cfix->iscache, &section, &laddr, isid);
1016         ptu_int_eq(errcode, -pte_bad_image);
1017
1018         return ptu_passed();
1019 }
1020
1021 static struct ptunit_result add_twice(struct iscache_fixture *cfix)
1022 {
1023         int isid[2];
1024
1025         isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1026         ptu_int_gt(isid[0], 0);
1027
1028         isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1029         ptu_int_gt(isid[1], 0);
1030
1031         /* The second add should be ignored. */
1032         ptu_int_eq(isid[1], isid[0]);
1033
1034         return ptu_passed();
1035 }
1036
1037 static struct ptunit_result add_same(struct iscache_fixture *cfix)
1038 {
1039         int isid[2];
1040
1041         isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1042         ptu_int_gt(isid[0], 0);
1043
1044         cfix->section[1]->offset = cfix->section[0]->offset;
1045         cfix->section[1]->size = cfix->section[0]->size;
1046
1047         isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[1], 0ull);
1048         ptu_int_gt(isid[1], 0);
1049
1050         /* The second add should be ignored. */
1051         ptu_int_eq(isid[1], isid[0]);
1052
1053         return ptu_passed();
1054 }
1055
1056 static struct ptunit_result
1057 add_twice_different_laddr(struct iscache_fixture *cfix)
1058 {
1059         int isid[2];
1060
1061         isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1062         ptu_int_gt(isid[0], 0);
1063
1064         isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[0], 1ull);
1065         ptu_int_gt(isid[1], 0);
1066
1067         /* We must get different identifiers. */
1068         ptu_int_ne(isid[1], isid[0]);
1069
1070         /* We attach twice and take two references - one for each entry. */
1071         ptu_int_eq(cfix->section[0]->ucount, 3);
1072         ptu_int_eq(cfix->section[0]->acount, 2);
1073
1074         return ptu_passed();
1075 }
1076
1077 static struct ptunit_result
1078 add_same_different_laddr(struct iscache_fixture *cfix)
1079 {
1080         int isid[2];
1081
1082         isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1083         ptu_int_gt(isid[0], 0);
1084
1085         cfix->section[1]->offset = cfix->section[0]->offset;
1086         cfix->section[1]->size = cfix->section[0]->size;
1087
1088         isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[1], 1ull);
1089         ptu_int_gt(isid[1], 0);
1090
1091         /* We must get different identifiers. */
1092         ptu_int_ne(isid[1], isid[0]);
1093
1094         return ptu_passed();
1095 }
1096
1097 static struct ptunit_result
1098 add_different_same_laddr(struct iscache_fixture *cfix)
1099 {
1100         int isid[2];
1101
1102         isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1103         ptu_int_gt(isid[0], 0);
1104
1105         isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[1], 0ull);
1106         ptu_int_gt(isid[1], 0);
1107
1108         /* We must get different identifiers. */
1109         ptu_int_ne(isid[1], isid[0]);
1110
1111         return ptu_passed();
1112 }
1113
1114 static struct ptunit_result add_file_same(struct iscache_fixture *cfix)
1115 {
1116         int isid[2];
1117
1118         isid[0] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull);
1119         ptu_int_gt(isid[0], 0);
1120
1121         isid[1] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull);
1122         ptu_int_gt(isid[1], 0);
1123
1124         /* The second add should be ignored. */
1125         ptu_int_eq(isid[1], isid[0]);
1126
1127         return ptu_passed();
1128 }
1129
1130 static struct ptunit_result
1131 add_file_same_different_laddr(struct iscache_fixture *cfix)
1132 {
1133         int isid[2];
1134
1135         isid[0] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull);
1136         ptu_int_gt(isid[0], 0);
1137
1138         isid[1] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 1ull);
1139         ptu_int_gt(isid[1], 0);
1140
1141         /* We must get different identifiers. */
1142         ptu_int_ne(isid[1], isid[0]);
1143
1144         return ptu_passed();
1145 }
1146
1147 static struct ptunit_result
1148 add_file_different_same_laddr(struct iscache_fixture *cfix)
1149 {
1150         int isid[2];
1151
1152         isid[0] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull);
1153         ptu_int_gt(isid[0], 0);
1154
1155         isid[1] = pt_iscache_add_file(&cfix->iscache, "name", 1ull, 1ull, 0ull);
1156         ptu_int_gt(isid[1], 0);
1157
1158         /* We must get different identifiers. */
1159         ptu_int_ne(isid[1], isid[0]);
1160
1161         return ptu_passed();
1162 }
1163
1164 static struct ptunit_result read(struct iscache_fixture *cfix)
1165 {
1166         uint8_t buffer[] = { 0xcc, 0xcc, 0xcc };
1167         int status, isid;
1168
1169         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1170         ptu_int_gt(isid, 0);
1171
1172         status = pt_iscache_read(&cfix->iscache, buffer, 2ull, isid, 0xa008ull);
1173         ptu_int_eq(status, 2);
1174         ptu_uint_eq(buffer[0], 0x8);
1175         ptu_uint_eq(buffer[1], 0x9);
1176         ptu_uint_eq(buffer[2], 0xcc);
1177
1178         return ptu_passed();
1179 }
1180
1181 static struct ptunit_result read_truncate(struct iscache_fixture *cfix)
1182 {
1183         uint8_t buffer[] = { 0xcc, 0xcc };
1184         int status, isid;
1185
1186         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1187         ptu_int_gt(isid, 0);
1188
1189         status = pt_iscache_read(&cfix->iscache, buffer, sizeof(buffer), isid,
1190                                  0xa00full);
1191         ptu_int_eq(status, 1);
1192         ptu_uint_eq(buffer[0], 0xf);
1193         ptu_uint_eq(buffer[1], 0xcc);
1194
1195         return ptu_passed();
1196 }
1197
1198 static struct ptunit_result read_bad_vaddr(struct iscache_fixture *cfix)
1199 {
1200         uint8_t buffer[] = { 0xcc };
1201         int status, isid;
1202
1203         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1204         ptu_int_gt(isid, 0);
1205
1206         status = pt_iscache_read(&cfix->iscache, buffer, 1ull, isid, 0xb000ull);
1207         ptu_int_eq(status, -pte_nomap);
1208         ptu_uint_eq(buffer[0], 0xcc);
1209
1210         return ptu_passed();
1211 }
1212
1213 static struct ptunit_result read_bad_isid(struct iscache_fixture *cfix)
1214 {
1215         uint8_t buffer[] = { 0xcc };
1216         int status, isid;
1217
1218         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1219         ptu_int_gt(isid, 0);
1220
1221         status = pt_iscache_read(&cfix->iscache, buffer, 1ull, isid + 1,
1222                                  0xa000ull);
1223         ptu_int_eq(status, -pte_bad_image);
1224         ptu_uint_eq(buffer[0], 0xcc);
1225
1226         return ptu_passed();
1227 }
1228
1229 static struct ptunit_result lru_map(struct iscache_fixture *cfix)
1230 {
1231         int status, isid;
1232
1233         cfix->iscache.limit = cfix->section[0]->size;
1234         ptu_uint_eq(cfix->iscache.used, 0ull);
1235         ptu_null(cfix->iscache.lru);
1236
1237         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1238         ptu_int_gt(isid, 0);
1239
1240         status = pt_section_map(cfix->section[0]);
1241         ptu_int_eq(status, 0);
1242
1243         status = pt_section_unmap(cfix->section[0]);
1244         ptu_int_eq(status, 0);
1245
1246         ptu_ptr(cfix->iscache.lru);
1247         ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]);
1248         ptu_null(cfix->iscache.lru->next);
1249         ptu_uint_eq(cfix->iscache.used, cfix->section[0]->size);
1250
1251         return ptu_passed();
1252 }
1253
1254 static struct ptunit_result lru_read(struct iscache_fixture *cfix)
1255 {
1256         uint8_t buffer[] = { 0xcc, 0xcc, 0xcc };
1257         int status, isid;
1258
1259         cfix->iscache.limit = cfix->section[0]->size;
1260         ptu_uint_eq(cfix->iscache.used, 0ull);
1261         ptu_null(cfix->iscache.lru);
1262
1263         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1264         ptu_int_gt(isid, 0);
1265
1266         status = pt_iscache_read(&cfix->iscache, buffer, 2ull, isid, 0xa008ull);
1267         ptu_int_eq(status, 2);
1268
1269         ptu_ptr(cfix->iscache.lru);
1270         ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]);
1271         ptu_null(cfix->iscache.lru->next);
1272         ptu_uint_eq(cfix->iscache.used, cfix->section[0]->size);
1273
1274         return ptu_passed();
1275 }
1276
1277 static struct ptunit_result lru_map_nodup(struct iscache_fixture *cfix)
1278 {
1279         int status, isid;
1280
1281         cfix->iscache.limit = 2 * cfix->section[0]->size;
1282         ptu_uint_eq(cfix->iscache.used, 0ull);
1283         ptu_null(cfix->iscache.lru);
1284
1285         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1286         ptu_int_gt(isid, 0);
1287
1288         status = pt_section_map(cfix->section[0]);
1289         ptu_int_eq(status, 0);
1290
1291         status = pt_section_unmap(cfix->section[0]);
1292         ptu_int_eq(status, 0);
1293
1294         status = pt_section_map(cfix->section[0]);
1295         ptu_int_eq(status, 0);
1296
1297         status = pt_section_unmap(cfix->section[0]);
1298         ptu_int_eq(status, 0);
1299
1300         ptu_ptr(cfix->iscache.lru);
1301         ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]);
1302         ptu_null(cfix->iscache.lru->next);
1303         ptu_uint_eq(cfix->iscache.used, cfix->section[0]->size);
1304
1305         return ptu_passed();
1306 }
1307
1308 static struct ptunit_result lru_map_too_big(struct iscache_fixture *cfix)
1309 {
1310         int status, isid;
1311
1312         cfix->iscache.limit = cfix->section[0]->size - 1;
1313         ptu_uint_eq(cfix->iscache.used, 0ull);
1314         ptu_null(cfix->iscache.lru);
1315
1316         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1317         ptu_int_gt(isid, 0);
1318
1319         status = pt_section_map(cfix->section[0]);
1320         ptu_int_eq(status, 0);
1321
1322         status = pt_section_unmap(cfix->section[0]);
1323         ptu_int_eq(status, 0);
1324
1325         ptu_null(cfix->iscache.lru);
1326         ptu_uint_eq(cfix->iscache.used, 0ull);
1327
1328         return ptu_passed();
1329 }
1330
1331 static struct ptunit_result lru_map_add_front(struct iscache_fixture *cfix)
1332 {
1333         int status, isid;
1334
1335         cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size;
1336         ptu_uint_eq(cfix->iscache.used, 0ull);
1337         ptu_null(cfix->iscache.lru);
1338
1339         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1340         ptu_int_gt(isid, 0);
1341
1342         isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull);
1343         ptu_int_gt(isid, 0);
1344
1345         status = pt_section_map(cfix->section[0]);
1346         ptu_int_eq(status, 0);
1347
1348         status = pt_section_unmap(cfix->section[0]);
1349         ptu_int_eq(status, 0);
1350
1351         status = pt_section_map(cfix->section[1]);
1352         ptu_int_eq(status, 0);
1353
1354         status = pt_section_unmap(cfix->section[1]);
1355         ptu_int_eq(status, 0);
1356
1357         ptu_ptr(cfix->iscache.lru);
1358         ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[1]);
1359         ptu_ptr(cfix->iscache.lru->next);
1360         ptu_ptr_eq(cfix->iscache.lru->next->section, cfix->section[0]);
1361         ptu_null(cfix->iscache.lru->next->next);
1362         ptu_uint_eq(cfix->iscache.used,
1363                     cfix->section[0]->size + cfix->section[1]->size);
1364
1365         return ptu_passed();
1366 }
1367
1368 static struct ptunit_result lru_map_move_front(struct iscache_fixture *cfix)
1369 {
1370         int status, isid;
1371
1372         cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size;
1373         ptu_uint_eq(cfix->iscache.used, 0ull);
1374         ptu_null(cfix->iscache.lru);
1375
1376         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1377         ptu_int_gt(isid, 0);
1378
1379         isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull);
1380         ptu_int_gt(isid, 0);
1381
1382         status = pt_section_map(cfix->section[0]);
1383         ptu_int_eq(status, 0);
1384
1385         status = pt_section_unmap(cfix->section[0]);
1386         ptu_int_eq(status, 0);
1387
1388         status = pt_section_map(cfix->section[1]);
1389         ptu_int_eq(status, 0);
1390
1391         status = pt_section_unmap(cfix->section[1]);
1392         ptu_int_eq(status, 0);
1393
1394         status = pt_section_map(cfix->section[0]);
1395         ptu_int_eq(status, 0);
1396
1397         status = pt_section_unmap(cfix->section[0]);
1398         ptu_int_eq(status, 0);
1399
1400         ptu_ptr(cfix->iscache.lru);
1401         ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]);
1402         ptu_ptr(cfix->iscache.lru->next);
1403         ptu_ptr_eq(cfix->iscache.lru->next->section, cfix->section[1]);
1404         ptu_null(cfix->iscache.lru->next->next);
1405         ptu_uint_eq(cfix->iscache.used,
1406                     cfix->section[0]->size + cfix->section[1]->size);
1407
1408         return ptu_passed();
1409 }
1410
1411 static struct ptunit_result lru_map_evict(struct iscache_fixture *cfix)
1412 {
1413         int status, isid;
1414
1415         cfix->iscache.limit = cfix->section[0]->size +
1416                 cfix->section[1]->size - 1;
1417         ptu_uint_eq(cfix->iscache.used, 0ull);
1418         ptu_null(cfix->iscache.lru);
1419
1420         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1421         ptu_int_gt(isid, 0);
1422
1423         isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull);
1424         ptu_int_gt(isid, 0);
1425
1426         status = pt_section_map(cfix->section[0]);
1427         ptu_int_eq(status, 0);
1428
1429         status = pt_section_unmap(cfix->section[0]);
1430         ptu_int_eq(status, 0);
1431
1432         status = pt_section_map(cfix->section[1]);
1433         ptu_int_eq(status, 0);
1434
1435         status = pt_section_unmap(cfix->section[1]);
1436         ptu_int_eq(status, 0);
1437
1438         ptu_ptr(cfix->iscache.lru);
1439         ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[1]);
1440         ptu_null(cfix->iscache.lru->next);
1441         ptu_uint_eq(cfix->iscache.used, cfix->section[1]->size);
1442
1443         return ptu_passed();
1444 }
1445
1446 static struct ptunit_result lru_bcache_evict(struct iscache_fixture *cfix)
1447 {
1448         int status, isid;
1449
1450         cfix->iscache.limit = 4 * cfix->section[0]->size +
1451                 cfix->section[1]->size - 1;
1452         ptu_uint_eq(cfix->iscache.used, 0ull);
1453         ptu_null(cfix->iscache.lru);
1454
1455         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1456         ptu_int_gt(isid, 0);
1457
1458         isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull);
1459         ptu_int_gt(isid, 0);
1460
1461         status = pt_section_map(cfix->section[0]);
1462         ptu_int_eq(status, 0);
1463
1464         status = pt_section_unmap(cfix->section[0]);
1465         ptu_int_eq(status, 0);
1466
1467         status = pt_section_map(cfix->section[1]);
1468         ptu_int_eq(status, 0);
1469
1470         status = pt_section_unmap(cfix->section[1]);
1471         ptu_int_eq(status, 0);
1472
1473         status = pt_section_request_bcache(cfix->section[0]);
1474         ptu_int_eq(status, 0);
1475
1476         ptu_ptr(cfix->iscache.lru);
1477         ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]);
1478         ptu_null(cfix->iscache.lru->next);
1479         ptu_uint_eq(cfix->iscache.used, 4 * cfix->section[0]->size);
1480
1481         return ptu_passed();
1482 }
1483
1484 static struct ptunit_result lru_bcache_clear(struct iscache_fixture *cfix)
1485 {
1486         int status, isid;
1487
1488         cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size;
1489         ptu_uint_eq(cfix->iscache.used, 0ull);
1490         ptu_null(cfix->iscache.lru);
1491
1492         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1493         ptu_int_gt(isid, 0);
1494
1495         isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull);
1496         ptu_int_gt(isid, 0);
1497
1498         status = pt_section_map(cfix->section[0]);
1499         ptu_int_eq(status, 0);
1500
1501         status = pt_section_unmap(cfix->section[0]);
1502         ptu_int_eq(status, 0);
1503
1504         status = pt_section_map(cfix->section[1]);
1505         ptu_int_eq(status, 0);
1506
1507         status = pt_section_unmap(cfix->section[1]);
1508         ptu_int_eq(status, 0);
1509
1510         status = pt_section_request_bcache(cfix->section[0]);
1511         ptu_int_eq(status, 0);
1512
1513         ptu_null(cfix->iscache.lru);
1514         ptu_uint_eq(cfix->iscache.used, 0ull);
1515
1516         return ptu_passed();
1517 }
1518
1519 static struct ptunit_result lru_limit_evict(struct iscache_fixture *cfix)
1520 {
1521         int status, isid;
1522
1523         cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size;
1524         ptu_uint_eq(cfix->iscache.used, 0ull);
1525         ptu_null(cfix->iscache.lru);
1526
1527         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1528         ptu_int_gt(isid, 0);
1529
1530         isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull);
1531         ptu_int_gt(isid, 0);
1532
1533         status = pt_section_map(cfix->section[0]);
1534         ptu_int_eq(status, 0);
1535
1536         status = pt_section_unmap(cfix->section[0]);
1537         ptu_int_eq(status, 0);
1538
1539         status = pt_section_map(cfix->section[1]);
1540         ptu_int_eq(status, 0);
1541
1542         status = pt_section_unmap(cfix->section[1]);
1543         ptu_int_eq(status, 0);
1544
1545         status = pt_iscache_set_limit(&cfix->iscache,
1546                                       cfix->section[0]->size +
1547                                       cfix->section[1]->size - 1);
1548         ptu_int_eq(status, 0);
1549
1550         ptu_ptr(cfix->iscache.lru);
1551         ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[1]);
1552         ptu_null(cfix->iscache.lru->next);
1553         ptu_uint_eq(cfix->iscache.used, cfix->section[1]->size);
1554
1555         return ptu_passed();
1556 }
1557
1558 static struct ptunit_result lru_clear(struct iscache_fixture *cfix)
1559 {
1560         int status, isid;
1561
1562         cfix->iscache.limit = cfix->section[0]->size;
1563         ptu_uint_eq(cfix->iscache.used, 0ull);
1564         ptu_null(cfix->iscache.lru);
1565
1566         isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1567         ptu_int_gt(isid, 0);
1568
1569         status = pt_section_map(cfix->section[0]);
1570         ptu_int_eq(status, 0);
1571
1572         status = pt_section_unmap(cfix->section[0]);
1573         ptu_int_eq(status, 0);
1574
1575         status = pt_iscache_clear(&cfix->iscache);
1576         ptu_int_eq(status, 0);
1577
1578         ptu_null(cfix->iscache.lru);
1579         ptu_uint_eq(cfix->iscache.used, 0ull);
1580
1581         return ptu_passed();
1582 }
1583
1584 static int worker_add(void *arg)
1585 {
1586         struct iscache_fixture *cfix;
1587         int it;
1588
1589         cfix = arg;
1590         if (!cfix)
1591                 return -pte_internal;
1592
1593         for (it = 0; it < num_iterations; ++it) {
1594                 uint64_t laddr;
1595                 int sec;
1596
1597                 laddr = 0x1000ull * (it % 23);
1598
1599                 for (sec = 0; sec < num_sections; ++sec) {
1600                         struct pt_section *section;
1601                         uint64_t addr;
1602                         int isid, errcode;
1603
1604                         isid = pt_iscache_add(&cfix->iscache,
1605                                               cfix->section[sec], laddr);
1606                         if (isid < 0)
1607                                 return isid;
1608
1609                         errcode = pt_iscache_lookup(&cfix->iscache, &section,
1610                                                     &addr, isid);
1611                         if (errcode < 0)
1612                                 return errcode;
1613
1614                         if (laddr != addr)
1615                                 return -pte_noip;
1616
1617                         /* We may not get the image we added but the image we
1618                          * get must have similar attributes.
1619                          *
1620                          * We're using the same filename string literal for all
1621                          * sections, though.
1622                          */
1623                         if (section->offset != cfix->section[sec]->offset)
1624                                 return -pte_bad_image;
1625
1626                         if (section->size != cfix->section[sec]->size)
1627                                 return -pte_bad_image;
1628
1629                         errcode = pt_section_put(section);
1630                         if (errcode < 0)
1631                                 return errcode;
1632                 }
1633         }
1634
1635         return 0;
1636 }
1637
1638 static int worker_add_file(void *arg)
1639 {
1640         struct iscache_fixture *cfix;
1641         int it;
1642
1643         cfix = arg;
1644         if (!cfix)
1645                 return -pte_internal;
1646
1647         for (it = 0; it < num_iterations; ++it) {
1648                 uint64_t offset, size, laddr;
1649                 int sec;
1650
1651                 offset = it % 7 == 0 ? 0x1000 : 0x2000;
1652                 size = it % 5 == 0 ? 0x1000 : 0x2000;
1653                 laddr = it % 3 == 0 ? 0x1000 : 0x2000;
1654
1655                 for (sec = 0; sec < num_sections; ++sec) {
1656                         struct pt_section *section;
1657                         uint64_t addr;
1658                         int isid, errcode;
1659
1660                         isid = pt_iscache_add_file(&cfix->iscache, "name",
1661                                                    offset, size, laddr);
1662                         if (isid < 0)
1663                                 return isid;
1664
1665                         errcode = pt_iscache_lookup(&cfix->iscache, &section,
1666                                                     &addr, isid);
1667                         if (errcode < 0)
1668                                 return errcode;
1669
1670                         if (laddr != addr)
1671                                 return -pte_noip;
1672
1673                         if (section->offset != offset)
1674                                 return -pte_bad_image;
1675
1676                         if (section->size != size)
1677                                 return -pte_bad_image;
1678
1679                         errcode = pt_section_put(section);
1680                         if (errcode < 0)
1681                                 return errcode;
1682                 }
1683         }
1684
1685         return 0;
1686 }
1687
1688 static int worker_map(void *arg)
1689 {
1690         struct iscache_fixture *cfix;
1691         int it, sec, status;
1692
1693         cfix = arg;
1694         if (!cfix)
1695                 return -pte_internal;
1696
1697         for (it = 0; it < num_iterations; ++it) {
1698                 for (sec = 0; sec < num_sections; ++sec) {
1699
1700                         status = pt_section_map(cfix->section[sec]);
1701                         if (status < 0)
1702                                 return status;
1703
1704                         status = pt_section_unmap(cfix->section[sec]);
1705                         if (status < 0)
1706                                 return status;
1707                 }
1708         }
1709
1710         return 0;
1711 }
1712
1713 static int worker_map_limit(void *arg)
1714 {
1715         struct iscache_fixture *cfix;
1716         uint64_t limits[] = { 0x8000, 0x3000, 0x12000, 0x0 }, limit;
1717         int it, sec, errcode, lim;
1718
1719         cfix = arg;
1720         if (!cfix)
1721                 return -pte_internal;
1722
1723         lim = 0;
1724         for (it = 0; it < num_iterations; ++it) {
1725                 for (sec = 0; sec < num_sections; ++sec) {
1726
1727                         errcode = pt_section_map(cfix->section[sec]);
1728                         if (errcode < 0)
1729                                 return errcode;
1730
1731                         errcode = pt_section_unmap(cfix->section[sec]);
1732                         if (errcode < 0)
1733                                 return errcode;
1734                 }
1735
1736                 if (it % 23 != 0)
1737                         continue;
1738
1739                 limit = limits[lim++];
1740                 lim %= sizeof(limits) / sizeof(*limits);
1741
1742                 errcode = pt_iscache_set_limit(&cfix->iscache, limit);
1743                 if (errcode < 0)
1744                         return errcode;
1745         }
1746
1747         return 0;
1748 }
1749
1750 static int worker_map_bcache(void *arg)
1751 {
1752         struct iscache_fixture *cfix;
1753         int it, sec, status;
1754
1755         cfix = arg;
1756         if (!cfix)
1757                 return -pte_internal;
1758
1759         for (it = 0; it < num_iterations; ++it) {
1760                 for (sec = 0; sec < num_sections; ++sec) {
1761                         struct pt_section *section;
1762
1763                         section = cfix->section[sec];
1764
1765                         status = pt_section_map(section);
1766                         if (status < 0)
1767                                 return status;
1768
1769                         if (it % 13 == 0) {
1770                                 status = pt_section_request_bcache(section);
1771                                 if (status < 0) {
1772                                         (void) pt_section_unmap(section);
1773                                         return status;
1774                                 }
1775                         }
1776
1777                         status = pt_section_unmap(section);
1778                         if (status < 0)
1779                                 return status;
1780                 }
1781         }
1782
1783         return 0;
1784 }
1785
1786 static int worker_add_map(void *arg)
1787 {
1788         struct iscache_fixture *cfix;
1789         struct pt_section *section;
1790         int it;
1791
1792         cfix = arg;
1793         if (!cfix)
1794                 return -pte_internal;
1795
1796         section = cfix->section[0];
1797         for (it = 0; it < num_iterations; ++it) {
1798                 uint64_t laddr;
1799                 int isid, errcode;
1800
1801                 laddr = (uint64_t) it << 3;
1802
1803                 isid = pt_iscache_add(&cfix->iscache, section, laddr);
1804                 if (isid < 0)
1805                         return isid;
1806
1807                 errcode = pt_section_map(section);
1808                 if (errcode < 0)
1809                         return errcode;
1810
1811                 errcode = pt_section_unmap(section);
1812                 if (errcode < 0)
1813                         return errcode;
1814         }
1815
1816         return 0;
1817 }
1818
1819 static int worker_add_clear(void *arg)
1820 {
1821         struct iscache_fixture *cfix;
1822         struct pt_section *section;
1823         int it;
1824
1825         cfix = arg;
1826         if (!cfix)
1827                 return -pte_internal;
1828
1829         section = cfix->section[0];
1830         for (it = 0; it < num_iterations; ++it) {
1831                 uint64_t laddr;
1832                 int isid, errcode;
1833
1834                 laddr = (uint64_t) it << 3;
1835
1836                 isid = pt_iscache_add(&cfix->iscache, section, laddr);
1837                 if (isid < 0)
1838                         return isid;
1839
1840                 errcode = pt_iscache_clear(&cfix->iscache);
1841                 if (errcode < 0)
1842                         return errcode;
1843         }
1844
1845         return 0;
1846 }
1847
1848 static int worker_add_file_map(void *arg)
1849 {
1850         struct iscache_fixture *cfix;
1851         int it;
1852
1853         cfix = arg;
1854         if (!cfix)
1855                 return -pte_internal;
1856
1857         for (it = 0; it < num_iterations; ++it) {
1858                 struct pt_section *section;
1859                 uint64_t offset, size, laddr, addr;
1860                 int isid, errcode;
1861
1862                 offset = it % 7 < 4 ? 0x1000 : 0x2000;
1863                 size = it % 5 < 3 ? 0x1000 : 0x2000;
1864                 laddr = it % 3 < 2 ? 0x1000 : 0x2000;
1865
1866                 isid = pt_iscache_add_file(&cfix->iscache, "name",
1867                                            offset, size, laddr);
1868                 if (isid < 0)
1869                         return isid;
1870
1871                 errcode = pt_iscache_lookup(&cfix->iscache, &section,
1872                                             &addr, isid);
1873                 if (errcode < 0)
1874                         return errcode;
1875
1876                 if (addr != laddr)
1877                         return -pte_internal;
1878
1879                 errcode = pt_section_map(section);
1880                 if (errcode < 0)
1881                         return errcode;
1882
1883                 errcode = pt_section_unmap(section);
1884                 if (errcode < 0)
1885                         return errcode;
1886         }
1887
1888         return 0;
1889 }
1890
1891 static int worker_add_file_clear(void *arg)
1892 {
1893         struct iscache_fixture *cfix;
1894         int it;
1895
1896         cfix = arg;
1897         if (!cfix)
1898                 return -pte_internal;
1899
1900         for (it = 0; it < num_iterations; ++it) {
1901                 uint64_t offset, size, laddr;
1902                 int isid, errcode;
1903
1904                 offset = it % 7 < 4 ? 0x1000 : 0x2000;
1905                 size = it % 5 < 3 ? 0x1000 : 0x2000;
1906                 laddr = it % 3 < 2 ? 0x1000 : 0x2000;
1907
1908                 isid = pt_iscache_add_file(&cfix->iscache, "name",
1909                                            offset, size, laddr);
1910                 if (isid < 0)
1911                         return isid;
1912
1913                 if (it % 11 < 9)
1914                         continue;
1915
1916                 errcode = pt_iscache_clear(&cfix->iscache);
1917                 if (errcode < 0)
1918                         return errcode;
1919         }
1920
1921         return 0;
1922 }
1923
1924 static struct ptunit_result stress(struct iscache_fixture *cfix,
1925                                    int (*worker)(void *))
1926 {
1927         int errcode;
1928
1929 #if defined(FEATURE_THREADS)
1930         {
1931                 int thrd;
1932
1933                 for (thrd = 0; thrd < num_threads; ++thrd)
1934                         ptu_test(ptunit_thrd_create, &cfix->thrd, worker, cfix);
1935         }
1936 #endif /* defined(FEATURE_THREADS) */
1937
1938         errcode = worker(cfix);
1939         ptu_int_eq(errcode, 0);
1940
1941         return ptu_passed();
1942 }
1943 int main(int argc, char **argv)
1944 {
1945         struct iscache_fixture cfix, dfix, sfix;
1946         struct ptunit_suite suite;
1947
1948         cfix.init = cfix_init;
1949         cfix.fini = cfix_fini;
1950
1951         dfix.init = dfix_init;
1952         dfix.fini = cfix_fini;
1953
1954         sfix.init = sfix_init;
1955         sfix.fini = cfix_fini;
1956
1957         suite = ptunit_mk_suite(argc, argv);
1958
1959         ptu_run(suite, init_null);
1960         ptu_run(suite, fini_null);
1961         ptu_run(suite, name_null);
1962         ptu_run(suite, add_null);
1963         ptu_run(suite, find_null);
1964         ptu_run(suite, lookup_null);
1965         ptu_run(suite, clear_null);
1966         ptu_run(suite, free_null);
1967         ptu_run(suite, add_file_null);
1968         ptu_run(suite, read_null);
1969
1970         ptu_run_f(suite, name, dfix);
1971         ptu_run_f(suite, name_none, dfix);
1972
1973         ptu_run_f(suite, init_fini, cfix);
1974         ptu_run_f(suite, add, cfix);
1975         ptu_run_f(suite, add_no_name, cfix);
1976         ptu_run_f(suite, add_file, cfix);
1977
1978         ptu_run_f(suite, find, cfix);
1979         ptu_run_f(suite, find_empty, cfix);
1980         ptu_run_f(suite, find_bad_filename, cfix);
1981         ptu_run_f(suite, find_null_filename, cfix);
1982         ptu_run_f(suite, find_bad_offset, cfix);
1983         ptu_run_f(suite, find_bad_size, cfix);
1984         ptu_run_f(suite, find_bad_laddr, cfix);
1985
1986         ptu_run_f(suite, lookup, cfix);
1987         ptu_run_f(suite, lookup_bad_isid, cfix);
1988
1989         ptu_run_f(suite, clear_empty, cfix);
1990         ptu_run_f(suite, clear_find, cfix);
1991         ptu_run_f(suite, clear_lookup, cfix);
1992
1993         ptu_run_f(suite, add_twice, cfix);
1994         ptu_run_f(suite, add_same, cfix);
1995         ptu_run_f(suite, add_twice_different_laddr, cfix);
1996         ptu_run_f(suite, add_same_different_laddr, cfix);
1997         ptu_run_f(suite, add_different_same_laddr, cfix);
1998
1999         ptu_run_f(suite, add_file_same, cfix);
2000         ptu_run_f(suite, add_file_same_different_laddr, cfix);
2001         ptu_run_f(suite, add_file_different_same_laddr, cfix);
2002
2003         ptu_run_f(suite, read, cfix);
2004         ptu_run_f(suite, read_truncate, cfix);
2005         ptu_run_f(suite, read_bad_vaddr, cfix);
2006         ptu_run_f(suite, read_bad_isid, cfix);
2007
2008         ptu_run_f(suite, lru_map, cfix);
2009         ptu_run_f(suite, lru_read, cfix);
2010         ptu_run_f(suite, lru_map_nodup, cfix);
2011         ptu_run_f(suite, lru_map_too_big, cfix);
2012         ptu_run_f(suite, lru_map_add_front, cfix);
2013         ptu_run_f(suite, lru_map_move_front, cfix);
2014         ptu_run_f(suite, lru_map_evict, cfix);
2015         ptu_run_f(suite, lru_limit_evict, cfix);
2016         ptu_run_f(suite, lru_bcache_evict, cfix);
2017         ptu_run_f(suite, lru_bcache_clear, cfix);
2018         ptu_run_f(suite, lru_clear, cfix);
2019
2020         ptu_run_fp(suite, stress, cfix, worker_add);
2021         ptu_run_fp(suite, stress, cfix, worker_add_file);
2022         ptu_run_fp(suite, stress, sfix, worker_map);
2023         ptu_run_fp(suite, stress, sfix, worker_map_limit);
2024         ptu_run_fp(suite, stress, sfix, worker_map_bcache);
2025         ptu_run_fp(suite, stress, cfix, worker_add_map);
2026         ptu_run_fp(suite, stress, cfix, worker_add_clear);
2027         ptu_run_fp(suite, stress, cfix, worker_add_file_map);
2028         ptu_run_fp(suite, stress, cfix, worker_add_file_clear);
2029
2030         return ptunit_report(&suite);
2031 }