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 }
2032