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