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