diff options
Diffstat (limited to 'libipt/test/src/ptunit-image_section_cache.c')
-rw-r--r-- | libipt/test/src/ptunit-image_section_cache.c | 2031 |
1 files changed, 2031 insertions, 0 deletions
diff --git a/libipt/test/src/ptunit-image_section_cache.c b/libipt/test/src/ptunit-image_section_cache.c new file mode 100644 index 0000000000000..b94e733ae97fa --- /dev/null +++ b/libipt/test/src/ptunit-image_section_cache.c @@ -0,0 +1,2031 @@ +/* + * Copyright (c) 2016-2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pt_image_section_cache.h" + +#include "ptunit_threads.h" + +#include "intel-pt.h" + +#include <stdlib.h> + + +struct pt_section { + /* The filename. We only support string literals for testing. */ + const char *filename; + + /* The file offset and size. */ + uint64_t offset; + uint64_t size; + + /* The bcache size. */ + uint64_t bcsize; + + /* The iscache back link. */ + struct pt_image_section_cache *iscache; + + /* The file content. */ + uint8_t content[0x10]; + + /* The use count. */ + int ucount; + + /* The attach count. */ + int acount; + + /* The map count. */ + int mcount; + +#if defined(FEATURE_THREADS) + /* A lock protecting this section. */ + mtx_t lock; + /* A lock protecting the iscache and acount fields. */ + mtx_t alock; +#endif /* defined(FEATURE_THREADS) */ +}; + +extern int pt_mk_section(struct pt_section **psection, const char *filename, + uint64_t offset, uint64_t size); + +extern int pt_section_get(struct pt_section *section); +extern int pt_section_put(struct pt_section *section); +extern int pt_section_attach(struct pt_section *section, + struct pt_image_section_cache *iscache); +extern int pt_section_detach(struct pt_section *section, + struct pt_image_section_cache *iscache); + +extern int pt_section_map(struct pt_section *section); +extern int pt_section_map_share(struct pt_section *section); +extern int pt_section_unmap(struct pt_section *section); +extern int pt_section_request_bcache(struct pt_section *section); + +extern const char *pt_section_filename(const struct pt_section *section); +extern uint64_t pt_section_offset(const struct pt_section *section); +extern uint64_t pt_section_size(const struct pt_section *section); +extern int pt_section_memsize(struct pt_section *section, uint64_t *size); + +extern int pt_section_read(const struct pt_section *section, uint8_t *buffer, + uint16_t size, uint64_t offset); + + +int pt_mk_section(struct pt_section **psection, const char *filename, + uint64_t offset, uint64_t size) +{ + struct pt_section *section; + uint8_t idx; + + section = malloc(sizeof(*section)); + if (!section) + return -pte_nomem; + + memset(section, 0, sizeof(*section)); + section->filename = filename; + section->offset = offset; + section->size = size; + section->ucount = 1; + + for (idx = 0; idx < sizeof(section->content); ++idx) + section->content[idx] = idx; + +#if defined(FEATURE_THREADS) + { + int errcode; + + errcode = mtx_init(§ion->lock, mtx_plain); + if (errcode != thrd_success) { + free(section); + return -pte_bad_lock; + } + + errcode = mtx_init(§ion->alock, mtx_plain); + if (errcode != thrd_success) { + mtx_destroy(§ion->lock); + free(section); + return -pte_bad_lock; + } + } +#endif /* defined(FEATURE_THREADS) */ + + *psection = section; + + return 0; +} + +static int pt_section_lock(struct pt_section *section) +{ + if (!section) + return -pte_internal; + +#if defined(FEATURE_THREADS) + { + int errcode; + + errcode = mtx_lock(§ion->lock); + if (errcode != thrd_success) + return -pte_bad_lock; + } +#endif /* defined(FEATURE_THREADS) */ + + return 0; +} + +static int pt_section_unlock(struct pt_section *section) +{ + if (!section) + return -pte_internal; + +#if defined(FEATURE_THREADS) + { + int errcode; + + errcode = mtx_unlock(§ion->lock); + if (errcode != thrd_success) + return -pte_bad_lock; + } +#endif /* defined(FEATURE_THREADS) */ + + return 0; +} + +static int pt_section_lock_attach(struct pt_section *section) +{ + if (!section) + return -pte_internal; + +#if defined(FEATURE_THREADS) + { + int errcode; + + errcode = mtx_lock(§ion->alock); + if (errcode != thrd_success) + return -pte_bad_lock; + } +#endif /* defined(FEATURE_THREADS) */ + + return 0; +} + +static int pt_section_unlock_attach(struct pt_section *section) +{ + if (!section) + return -pte_internal; + +#if defined(FEATURE_THREADS) + { + int errcode; + + errcode = mtx_unlock(§ion->alock); + if (errcode != thrd_success) + return -pte_bad_lock; + } +#endif /* defined(FEATURE_THREADS) */ + + return 0; +} + +int pt_section_get(struct pt_section *section) +{ + int errcode, ucount; + + if (!section) + return -pte_internal; + + errcode = pt_section_lock(section); + if (errcode < 0) + return errcode; + + ucount = ++section->ucount; + + errcode = pt_section_unlock(section); + if (errcode < 0) + return errcode; + + if (!ucount) + return -pte_internal; + + return 0; +} + +int pt_section_put(struct pt_section *section) +{ + int errcode, ucount; + + if (!section) + return -pte_internal; + + errcode = pt_section_lock(section); + if (errcode < 0) + return errcode; + + ucount = --section->ucount; + + errcode = pt_section_unlock(section); + if (errcode < 0) + return errcode; + + if (!ucount) { +#if defined(FEATURE_THREADS) + mtx_destroy(§ion->alock); + mtx_destroy(§ion->lock); +#endif /* defined(FEATURE_THREADS) */ + free(section); + } + + return 0; +} + +int pt_section_attach(struct pt_section *section, + struct pt_image_section_cache *iscache) +{ + int errcode, ucount, acount; + + if (!section || !iscache) + return -pte_internal; + + errcode = pt_section_lock_attach(section); + if (errcode < 0) + return errcode; + + ucount = section->ucount; + acount = section->acount; + if (!acount) { + if (section->iscache || !ucount) + goto out_unlock; + + section->iscache = iscache; + section->acount = 1; + + return pt_section_unlock_attach(section); + } + + acount += 1; + if (!acount) { + (void) pt_section_unlock_attach(section); + return -pte_overflow; + } + + if (ucount < acount) + goto out_unlock; + + if (section->iscache != iscache) + goto out_unlock; + + section->acount = acount; + + return pt_section_unlock_attach(section); + + out_unlock: + (void) pt_section_unlock_attach(section); + return -pte_internal; +} + +int pt_section_detach(struct pt_section *section, + struct pt_image_section_cache *iscache) +{ + int errcode, ucount, acount; + + if (!section || !iscache) + return -pte_internal; + + errcode = pt_section_lock_attach(section); + if (errcode < 0) + return errcode; + + if (section->iscache != iscache) + goto out_unlock; + + acount = section->acount; + if (!acount) + goto out_unlock; + + acount -= 1; + ucount = section->ucount; + if (ucount < acount) + goto out_unlock; + + section->acount = acount; + if (!acount) + section->iscache = NULL; + + return pt_section_unlock_attach(section); + + out_unlock: + (void) pt_section_unlock_attach(section); + return -pte_internal; +} + +int pt_section_map(struct pt_section *section) +{ + struct pt_image_section_cache *iscache; + int errcode, status; + + if (!section) + return -pte_internal; + + errcode = pt_section_map_share(section); + if (errcode < 0) + return errcode; + + errcode = pt_section_lock_attach(section); + if (errcode < 0) + return errcode; + + status = 0; + iscache = section->iscache; + if (iscache) + status = pt_iscache_notify_map(iscache, section); + + errcode = pt_section_unlock_attach(section); + + return (status < 0) ? status : errcode; +} + +int pt_section_map_share(struct pt_section *section) +{ + int errcode, mcount; + + if (!section) + return -pte_internal; + + errcode = pt_section_lock(section); + if (errcode < 0) + return errcode; + + mcount = ++section->mcount; + + errcode = pt_section_unlock(section); + if (errcode < 0) + return errcode; + + if (mcount <= 0) + return -pte_internal; + + return 0; +} + +int pt_section_unmap(struct pt_section *section) +{ + int errcode, mcount; + + if (!section) + return -pte_internal; + + errcode = pt_section_lock(section); + if (errcode < 0) + return errcode; + + section->bcsize = 0ull; + mcount = --section->mcount; + + errcode = pt_section_unlock(section); + if (errcode < 0) + return errcode; + + if (mcount < 0) + return -pte_internal; + + return 0; +} + +int pt_section_request_bcache(struct pt_section *section) +{ + struct pt_image_section_cache *iscache; + uint64_t memsize; + int errcode; + + if (!section) + return -pte_internal; + + errcode = pt_section_lock_attach(section); + if (errcode < 0) + return errcode; + + errcode = pt_section_lock(section); + if (errcode < 0) + goto out_alock; + + if (section->bcsize) + goto out_lock; + + section->bcsize = section->size * 3; + memsize = section->size + section->bcsize; + + errcode = pt_section_unlock(section); + if (errcode < 0) + goto out_alock; + + iscache = section->iscache; + if (iscache) { + errcode = pt_iscache_notify_resize(iscache, section, memsize); + if (errcode < 0) + goto out_alock; + } + + return pt_section_unlock_attach(section); + + +out_lock: + (void) pt_section_unlock(section); + +out_alock: + (void) pt_section_unlock_attach(section); + return errcode; +} + +const char *pt_section_filename(const struct pt_section *section) +{ + if (!section) + return NULL; + + return section->filename; +} + +uint64_t pt_section_offset(const struct pt_section *section) +{ + if (!section) + return 0ull; + + return section->offset; +} + +uint64_t pt_section_size(const struct pt_section *section) +{ + if (!section) + return 0ull; + + return section->size; +} + +int pt_section_memsize(struct pt_section *section, uint64_t *size) +{ + if (!section || !size) + return -pte_internal; + + *size = section->mcount ? section->size + section->bcsize : 0ull; + + return 0; +} + +int pt_section_read(const struct pt_section *section, uint8_t *buffer, + uint16_t size, uint64_t offset) +{ + uint64_t begin, end, max; + + if (!section || !buffer) + return -pte_internal; + + begin = offset; + end = begin + size; + max = sizeof(section->content); + + if (max <= begin) + return -pte_nomap; + + if (max < end) + end = max; + + if (end <= begin) + return -pte_invalid; + + memcpy(buffer, §ion->content[begin], (size_t) (end - begin)); + return (int) (end - begin); +} + +enum { + /* The number of test sections. */ + num_sections = 8, + +#if defined(FEATURE_THREADS) + + num_threads = 8, + +#endif /* defined(FEATURE_THREADS) */ + + num_iterations = 0x1000 +}; + +struct iscache_fixture { + /* Threading support. */ + struct ptunit_thrd_fixture thrd; + + /* The image section cache under test. */ + struct pt_image_section_cache iscache; + + /* A bunch of test sections. */ + struct pt_section *section[num_sections]; + + /* The test fixture initialization and finalization functions. */ + struct ptunit_result (*init)(struct iscache_fixture *); + struct ptunit_result (*fini)(struct iscache_fixture *); +}; + +static struct ptunit_result dfix_init(struct iscache_fixture *cfix) +{ + int idx; + + ptu_test(ptunit_thrd_init, &cfix->thrd); + + memset(cfix->section, 0, sizeof(cfix->section)); + + for (idx = 0; idx < num_sections; ++idx) { + struct pt_section *section; + int errcode; + + errcode = pt_mk_section(§ion, "some-filename", + idx % 3 == 0 ? 0x1000 : 0x2000, + idx % 2 == 0 ? 0x1000 : 0x2000); + ptu_int_eq(errcode, 0); + ptu_ptr(section); + + cfix->section[idx] = section; + } + + return ptu_passed(); +} + +static struct ptunit_result cfix_init(struct iscache_fixture *cfix) +{ + int errcode; + + ptu_test(dfix_init, cfix); + + errcode = pt_iscache_init(&cfix->iscache, NULL); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result sfix_init(struct iscache_fixture *cfix) +{ + int status, idx; + + ptu_test(cfix_init, cfix); + + cfix->iscache.limit = 0x7800; + + for (idx = 0; idx < num_sections; ++idx) { + status = pt_iscache_add(&cfix->iscache, cfix->section[idx], + 0ull); + ptu_int_ge(status, 0); + } + + return ptu_passed(); +} + +static struct ptunit_result cfix_fini(struct iscache_fixture *cfix) +{ + int idx, errcode; + + ptu_test(ptunit_thrd_fini, &cfix->thrd); + + for (idx = 0; idx < cfix->thrd.nthreads; ++idx) + ptu_int_eq(cfix->thrd.result[idx], 0); + + pt_iscache_fini(&cfix->iscache); + + for (idx = 0; idx < num_sections; ++idx) { + ptu_int_eq(cfix->section[idx]->ucount, 1); + ptu_int_eq(cfix->section[idx]->acount, 0); + ptu_int_eq(cfix->section[idx]->mcount, 0); + ptu_null(cfix->section[idx]->iscache); + + errcode = pt_section_put(cfix->section[idx]); + ptu_int_eq(errcode, 0); + } + + return ptu_passed(); +} + + +static struct ptunit_result init_null(void) +{ + int errcode; + + errcode = pt_iscache_init(NULL, NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result fini_null(void) +{ + pt_iscache_fini(NULL); + + return ptu_passed(); +} + +static struct ptunit_result name_null(void) +{ + const char *name; + + name = pt_iscache_name(NULL); + ptu_null(name); + + return ptu_passed(); +} + +static struct ptunit_result add_null(void) +{ + struct pt_image_section_cache iscache; + struct pt_section section; + int errcode; + + errcode = pt_iscache_add(NULL, §ion, 0ull); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_iscache_add(&iscache, NULL, 0ull); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result find_null(void) +{ + int errcode; + + errcode = pt_iscache_find(NULL, "filename", 0ull, 0ull, 0ull); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result lookup_null(void) +{ + struct pt_image_section_cache iscache; + struct pt_section *section; + uint64_t laddr; + int errcode; + + errcode = pt_iscache_lookup(NULL, §ion, &laddr, 0); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_iscache_lookup(&iscache, NULL, &laddr, 0); + ptu_int_eq(errcode, -pte_internal); + + errcode = pt_iscache_lookup(&iscache, §ion, NULL, 0); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result clear_null(void) +{ + int errcode; + + errcode = pt_iscache_clear(NULL); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result free_null(void) +{ + pt_iscache_free(NULL); + + return ptu_passed(); +} + +static struct ptunit_result add_file_null(void) +{ + struct pt_image_section_cache iscache; + int errcode; + + errcode = pt_iscache_add_file(NULL, "filename", 0ull, 0ull, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_iscache_add_file(&iscache, NULL, 0ull, 0ull, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result read_null(void) +{ + struct pt_image_section_cache iscache; + uint8_t buffer; + int errcode; + + errcode = pt_iscache_read(NULL, &buffer, sizeof(buffer), 1ull, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_iscache_read(&iscache, NULL, sizeof(buffer), 1ull, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + errcode = pt_iscache_read(&iscache, &buffer, 0ull, 1, 0ull); + ptu_int_eq(errcode, -pte_invalid); + + return ptu_passed(); +} + +static struct ptunit_result init_fini(struct iscache_fixture *cfix) +{ + (void) cfix; + + /* The actual init and fini calls are in cfix_init() and cfix_fini(). */ + return ptu_passed(); +} + +static struct ptunit_result name(struct iscache_fixture *cfix) +{ + const char *name; + + pt_iscache_init(&cfix->iscache, "iscache-name"); + + name = pt_iscache_name(&cfix->iscache); + ptu_str_eq(name, "iscache-name"); + + return ptu_passed(); +} + +static struct ptunit_result name_none(struct iscache_fixture *cfix) +{ + const char *name; + + pt_iscache_init(&cfix->iscache, NULL); + + name = pt_iscache_name(&cfix->iscache); + ptu_null(name); + + return ptu_passed(); +} + +static struct ptunit_result add(struct iscache_fixture *cfix) +{ + int isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid, 0); + + /* The cache attaches and gets a reference on success. */ + ptu_int_eq(cfix->section[0]->ucount, 2); + ptu_int_eq(cfix->section[0]->acount, 1); + + /* The added section must be implicitly put in pt_iscache_fini. */ + return ptu_passed(); +} + +static struct ptunit_result add_no_name(struct iscache_fixture *cfix) +{ + struct pt_section section; + int errcode; + + memset(§ion, 0, sizeof(section)); + + errcode = pt_iscache_add(&cfix->iscache, §ion, 0ull); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result add_file(struct iscache_fixture *cfix) +{ + int isid; + + isid = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull); + ptu_int_gt(isid, 0); + + return ptu_passed(); +} + +static struct ptunit_result find(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int found, isid; + + section = cfix->section[0]; + ptu_ptr(section); + + isid = pt_iscache_add(&cfix->iscache, section, 0ull); + ptu_int_gt(isid, 0); + + found = pt_iscache_find(&cfix->iscache, section->filename, + section->offset, section->size, 0ull); + ptu_int_eq(found, isid); + + return ptu_passed(); +} + +static struct ptunit_result find_empty(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int found; + + section = cfix->section[0]; + ptu_ptr(section); + + found = pt_iscache_find(&cfix->iscache, section->filename, + section->offset, section->size, 0ull); + ptu_int_eq(found, 0); + + return ptu_passed(); +} + +static struct ptunit_result find_bad_filename(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int found, isid; + + section = cfix->section[0]; + ptu_ptr(section); + + isid = pt_iscache_add(&cfix->iscache, section, 0ull); + ptu_int_gt(isid, 0); + + found = pt_iscache_find(&cfix->iscache, "bad-filename", + section->offset, section->size, 0ull); + ptu_int_eq(found, 0); + + return ptu_passed(); +} + +static struct ptunit_result find_null_filename(struct iscache_fixture *cfix) +{ + int errcode; + + errcode = pt_iscache_find(&cfix->iscache, NULL, 0ull, 0ull, 0ull); + ptu_int_eq(errcode, -pte_internal); + + return ptu_passed(); +} + +static struct ptunit_result find_bad_offset(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int found, isid; + + section = cfix->section[0]; + ptu_ptr(section); + + isid = pt_iscache_add(&cfix->iscache, section, 0ull); + ptu_int_gt(isid, 0); + + found = pt_iscache_find(&cfix->iscache, section->filename, 0ull, + section->size, 0ull); + ptu_int_eq(found, 0); + + return ptu_passed(); +} + +static struct ptunit_result find_bad_size(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int found, isid; + + section = cfix->section[0]; + ptu_ptr(section); + + isid = pt_iscache_add(&cfix->iscache, section, 0ull); + ptu_int_gt(isid, 0); + + found = pt_iscache_find(&cfix->iscache, section->filename, + section->offset, 0ull, 0ull); + ptu_int_eq(found, 0); + + return ptu_passed(); +} + +static struct ptunit_result find_bad_laddr(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int found, isid; + + section = cfix->section[0]; + ptu_ptr(section); + + isid = pt_iscache_add(&cfix->iscache, section, 0ull); + ptu_int_gt(isid, 0); + + found = pt_iscache_find(&cfix->iscache, section->filename, + section->offset, section->size, 1ull); + ptu_int_eq(found, 0); + + return ptu_passed(); +} + +static struct ptunit_result lookup(struct iscache_fixture *cfix) +{ + struct pt_section *section; + uint64_t laddr; + int errcode, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid, 0); + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, isid); + ptu_int_eq(errcode, 0); + ptu_ptr_eq(section, cfix->section[0]); + ptu_uint_eq(laddr, 0ull); + + errcode = pt_section_put(section); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result lookup_bad_isid(struct iscache_fixture *cfix) +{ + struct pt_section *section; + uint64_t laddr; + int errcode, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid, 0); + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, 0); + ptu_int_eq(errcode, -pte_bad_image); + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, -isid); + ptu_int_eq(errcode, -pte_bad_image); + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, isid + 1); + ptu_int_eq(errcode, -pte_bad_image); + + return ptu_passed(); +} + +static struct ptunit_result clear_empty(struct iscache_fixture *cfix) +{ + int errcode; + + errcode = pt_iscache_clear(&cfix->iscache); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} + +static struct ptunit_result clear_find(struct iscache_fixture *cfix) +{ + struct pt_section *section; + int errcode, found, isid; + + section = cfix->section[0]; + ptu_ptr(section); + + isid = pt_iscache_add(&cfix->iscache, section, 0ull); + ptu_int_gt(isid, 0); + + errcode = pt_iscache_clear(&cfix->iscache); + ptu_int_eq(errcode, 0); + + + found = pt_iscache_find(&cfix->iscache, section->filename, + section->offset, section->size, 0ull); + ptu_int_eq(found, 0); + + return ptu_passed(); +} + +static struct ptunit_result clear_lookup(struct iscache_fixture *cfix) +{ + struct pt_section *section; + uint64_t laddr; + int errcode, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid, 0); + + errcode = pt_iscache_clear(&cfix->iscache); + ptu_int_eq(errcode, 0); + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, isid); + ptu_int_eq(errcode, -pte_bad_image); + + return ptu_passed(); +} + +static struct ptunit_result add_twice(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid[0], 0); + + isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid[1], 0); + + /* The second add should be ignored. */ + ptu_int_eq(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result add_same(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid[0], 0); + + cfix->section[1]->offset = cfix->section[0]->offset; + cfix->section[1]->size = cfix->section[0]->size; + + isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[1], 0ull); + ptu_int_gt(isid[1], 0); + + /* The second add should be ignored. */ + ptu_int_eq(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result +add_twice_different_laddr(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid[0], 0); + + isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[0], 1ull); + ptu_int_gt(isid[1], 0); + + /* We must get different identifiers. */ + ptu_int_ne(isid[1], isid[0]); + + /* We attach twice and take two references - one for each entry. */ + ptu_int_eq(cfix->section[0]->ucount, 3); + ptu_int_eq(cfix->section[0]->acount, 2); + + return ptu_passed(); +} + +static struct ptunit_result +add_same_different_laddr(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid[0], 0); + + cfix->section[1]->offset = cfix->section[0]->offset; + cfix->section[1]->size = cfix->section[0]->size; + + isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[1], 1ull); + ptu_int_gt(isid[1], 0); + + /* We must get different identifiers. */ + ptu_int_ne(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result +add_different_same_laddr(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull); + ptu_int_gt(isid[0], 0); + + isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[1], 0ull); + ptu_int_gt(isid[1], 0); + + /* We must get different identifiers. */ + ptu_int_ne(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result add_file_same(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull); + ptu_int_gt(isid[0], 0); + + isid[1] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull); + ptu_int_gt(isid[1], 0); + + /* The second add should be ignored. */ + ptu_int_eq(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result +add_file_same_different_laddr(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull); + ptu_int_gt(isid[0], 0); + + isid[1] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 1ull); + ptu_int_gt(isid[1], 0); + + /* We must get different identifiers. */ + ptu_int_ne(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result +add_file_different_same_laddr(struct iscache_fixture *cfix) +{ + int isid[2]; + + isid[0] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull); + ptu_int_gt(isid[0], 0); + + isid[1] = pt_iscache_add_file(&cfix->iscache, "name", 1ull, 1ull, 0ull); + ptu_int_gt(isid[1], 0); + + /* We must get different identifiers. */ + ptu_int_ne(isid[1], isid[0]); + + return ptu_passed(); +} + +static struct ptunit_result read(struct iscache_fixture *cfix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_iscache_read(&cfix->iscache, buffer, 2ull, isid, 0xa008ull); + ptu_int_eq(status, 2); + ptu_uint_eq(buffer[0], 0x8); + ptu_uint_eq(buffer[1], 0x9); + ptu_uint_eq(buffer[2], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_truncate(struct iscache_fixture *cfix) +{ + uint8_t buffer[] = { 0xcc, 0xcc }; + int status, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_iscache_read(&cfix->iscache, buffer, sizeof(buffer), isid, + 0xa00full); + ptu_int_eq(status, 1); + ptu_uint_eq(buffer[0], 0xf); + ptu_uint_eq(buffer[1], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_bad_vaddr(struct iscache_fixture *cfix) +{ + uint8_t buffer[] = { 0xcc }; + int status, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_iscache_read(&cfix->iscache, buffer, 1ull, isid, 0xb000ull); + ptu_int_eq(status, -pte_nomap); + ptu_uint_eq(buffer[0], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result read_bad_isid(struct iscache_fixture *cfix) +{ + uint8_t buffer[] = { 0xcc }; + int status, isid; + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_iscache_read(&cfix->iscache, buffer, 1ull, isid + 1, + 0xa000ull); + ptu_int_eq(status, -pte_bad_image); + ptu_uint_eq(buffer[0], 0xcc); + + return ptu_passed(); +} + +static struct ptunit_result lru_map(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]); + ptu_null(cfix->iscache.lru->next); + ptu_uint_eq(cfix->iscache.used, cfix->section[0]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_read(struct iscache_fixture *cfix) +{ + uint8_t buffer[] = { 0xcc, 0xcc, 0xcc }; + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_iscache_read(&cfix->iscache, buffer, 2ull, isid, 0xa008ull); + ptu_int_eq(status, 2); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]); + ptu_null(cfix->iscache.lru->next); + ptu_uint_eq(cfix->iscache.used, cfix->section[0]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_map_nodup(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = 2 * cfix->section[0]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]); + ptu_null(cfix->iscache.lru->next); + ptu_uint_eq(cfix->iscache.used, cfix->section[0]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_map_too_big(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size - 1; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + ptu_null(cfix->iscache.lru); + ptu_uint_eq(cfix->iscache.used, 0ull); + + return ptu_passed(); +} + +static struct ptunit_result lru_map_add_front(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[1]); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[1]); + ptu_ptr(cfix->iscache.lru->next); + ptu_ptr_eq(cfix->iscache.lru->next->section, cfix->section[0]); + ptu_null(cfix->iscache.lru->next->next); + ptu_uint_eq(cfix->iscache.used, + cfix->section[0]->size + cfix->section[1]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_map_move_front(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]); + ptu_ptr(cfix->iscache.lru->next); + ptu_ptr_eq(cfix->iscache.lru->next->section, cfix->section[1]); + ptu_null(cfix->iscache.lru->next->next); + ptu_uint_eq(cfix->iscache.used, + cfix->section[0]->size + cfix->section[1]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_map_evict(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size + + cfix->section[1]->size - 1; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[1]); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[1]); + ptu_null(cfix->iscache.lru->next); + ptu_uint_eq(cfix->iscache.used, cfix->section[1]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_bcache_evict(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = 4 * cfix->section[0]->size + + cfix->section[1]->size - 1; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_request_bcache(cfix->section[0]); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]); + ptu_null(cfix->iscache.lru->next); + ptu_uint_eq(cfix->iscache.used, 4 * cfix->section[0]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_bcache_clear(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_request_bcache(cfix->section[0]); + ptu_int_eq(status, 0); + + ptu_null(cfix->iscache.lru); + ptu_uint_eq(cfix->iscache.used, 0ull); + + return ptu_passed(); +} + +static struct ptunit_result lru_limit_evict(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_map(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[1]); + ptu_int_eq(status, 0); + + status = pt_iscache_set_limit(&cfix->iscache, + cfix->section[0]->size + + cfix->section[1]->size - 1); + ptu_int_eq(status, 0); + + ptu_ptr(cfix->iscache.lru); + ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[1]); + ptu_null(cfix->iscache.lru->next); + ptu_uint_eq(cfix->iscache.used, cfix->section[1]->size); + + return ptu_passed(); +} + +static struct ptunit_result lru_clear(struct iscache_fixture *cfix) +{ + int status, isid; + + cfix->iscache.limit = cfix->section[0]->size; + ptu_uint_eq(cfix->iscache.used, 0ull); + ptu_null(cfix->iscache.lru); + + isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull); + ptu_int_gt(isid, 0); + + status = pt_section_map(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_section_unmap(cfix->section[0]); + ptu_int_eq(status, 0); + + status = pt_iscache_clear(&cfix->iscache); + ptu_int_eq(status, 0); + + ptu_null(cfix->iscache.lru); + ptu_uint_eq(cfix->iscache.used, 0ull); + + return ptu_passed(); +} + +static int worker_add(void *arg) +{ + struct iscache_fixture *cfix; + int it; + + cfix = arg; + if (!cfix) + return -pte_internal; + + for (it = 0; it < num_iterations; ++it) { + uint64_t laddr; + int sec; + + laddr = 0x1000ull * (it % 23); + + for (sec = 0; sec < num_sections; ++sec) { + struct pt_section *section; + uint64_t addr; + int isid, errcode; + + isid = pt_iscache_add(&cfix->iscache, + cfix->section[sec], laddr); + if (isid < 0) + return isid; + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, + &addr, isid); + if (errcode < 0) + return errcode; + + if (laddr != addr) + return -pte_noip; + + /* We may not get the image we added but the image we + * get must have similar attributes. + * + * We're using the same filename string literal for all + * sections, though. + */ + if (section->offset != cfix->section[sec]->offset) + return -pte_bad_image; + + if (section->size != cfix->section[sec]->size) + return -pte_bad_image; + + errcode = pt_section_put(section); + if (errcode < 0) + return errcode; + } + } + + return 0; +} + +static int worker_add_file(void *arg) +{ + struct iscache_fixture *cfix; + int it; + + cfix = arg; + if (!cfix) + return -pte_internal; + + for (it = 0; it < num_iterations; ++it) { + uint64_t offset, size, laddr; + int sec; + + offset = it % 7 == 0 ? 0x1000 : 0x2000; + size = it % 5 == 0 ? 0x1000 : 0x2000; + laddr = it % 3 == 0 ? 0x1000 : 0x2000; + + for (sec = 0; sec < num_sections; ++sec) { + struct pt_section *section; + uint64_t addr; + int isid, errcode; + + isid = pt_iscache_add_file(&cfix->iscache, "name", + offset, size, laddr); + if (isid < 0) + return isid; + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, + &addr, isid); + if (errcode < 0) + return errcode; + + if (laddr != addr) + return -pte_noip; + + if (section->offset != offset) + return -pte_bad_image; + + if (section->size != size) + return -pte_bad_image; + + errcode = pt_section_put(section); + if (errcode < 0) + return errcode; + } + } + + return 0; +} + +static int worker_map(void *arg) +{ + struct iscache_fixture *cfix; + int it, sec, status; + + cfix = arg; + if (!cfix) + return -pte_internal; + + for (it = 0; it < num_iterations; ++it) { + for (sec = 0; sec < num_sections; ++sec) { + + status = pt_section_map(cfix->section[sec]); + if (status < 0) + return status; + + status = pt_section_unmap(cfix->section[sec]); + if (status < 0) + return status; + } + } + + return 0; +} + +static int worker_map_limit(void *arg) +{ + struct iscache_fixture *cfix; + uint64_t limits[] = { 0x8000, 0x3000, 0x12000, 0x0 }, limit; + int it, sec, errcode, lim; + + cfix = arg; + if (!cfix) + return -pte_internal; + + lim = 0; + for (it = 0; it < num_iterations; ++it) { + for (sec = 0; sec < num_sections; ++sec) { + + errcode = pt_section_map(cfix->section[sec]); + if (errcode < 0) + return errcode; + + errcode = pt_section_unmap(cfix->section[sec]); + if (errcode < 0) + return errcode; + } + + if (it % 23 != 0) + continue; + + limit = limits[lim++]; + lim %= sizeof(limits) / sizeof(*limits); + + errcode = pt_iscache_set_limit(&cfix->iscache, limit); + if (errcode < 0) + return errcode; + } + + return 0; +} + +static int worker_map_bcache(void *arg) +{ + struct iscache_fixture *cfix; + int it, sec, status; + + cfix = arg; + if (!cfix) + return -pte_internal; + + for (it = 0; it < num_iterations; ++it) { + for (sec = 0; sec < num_sections; ++sec) { + struct pt_section *section; + + section = cfix->section[sec]; + + status = pt_section_map(section); + if (status < 0) + return status; + + if (it % 13 == 0) { + status = pt_section_request_bcache(section); + if (status < 0) { + (void) pt_section_unmap(section); + return status; + } + } + + status = pt_section_unmap(section); + if (status < 0) + return status; + } + } + + return 0; +} + +static int worker_add_map(void *arg) +{ + struct iscache_fixture *cfix; + struct pt_section *section; + int it; + + cfix = arg; + if (!cfix) + return -pte_internal; + + section = cfix->section[0]; + for (it = 0; it < num_iterations; ++it) { + uint64_t laddr; + int isid, errcode; + + laddr = (uint64_t) it << 3; + + isid = pt_iscache_add(&cfix->iscache, section, laddr); + if (isid < 0) + return isid; + + errcode = pt_section_map(section); + if (errcode < 0) + return errcode; + + errcode = pt_section_unmap(section); + if (errcode < 0) + return errcode; + } + + return 0; +} + +static int worker_add_clear(void *arg) +{ + struct iscache_fixture *cfix; + struct pt_section *section; + int it; + + cfix = arg; + if (!cfix) + return -pte_internal; + + section = cfix->section[0]; + for (it = 0; it < num_iterations; ++it) { + uint64_t laddr; + int isid, errcode; + + laddr = (uint64_t) it << 3; + + isid = pt_iscache_add(&cfix->iscache, section, laddr); + if (isid < 0) + return isid; + + errcode = pt_iscache_clear(&cfix->iscache); + if (errcode < 0) + return errcode; + } + + return 0; +} + +static int worker_add_file_map(void *arg) +{ + struct iscache_fixture *cfix; + int it; + + cfix = arg; + if (!cfix) + return -pte_internal; + + for (it = 0; it < num_iterations; ++it) { + struct pt_section *section; + uint64_t offset, size, laddr, addr; + int isid, errcode; + + offset = it % 7 < 4 ? 0x1000 : 0x2000; + size = it % 5 < 3 ? 0x1000 : 0x2000; + laddr = it % 3 < 2 ? 0x1000 : 0x2000; + + isid = pt_iscache_add_file(&cfix->iscache, "name", + offset, size, laddr); + if (isid < 0) + return isid; + + errcode = pt_iscache_lookup(&cfix->iscache, §ion, + &addr, isid); + if (errcode < 0) + return errcode; + + if (addr != laddr) + return -pte_internal; + + errcode = pt_section_map(section); + if (errcode < 0) + return errcode; + + errcode = pt_section_unmap(section); + if (errcode < 0) + return errcode; + } + + return 0; +} + +static int worker_add_file_clear(void *arg) +{ + struct iscache_fixture *cfix; + int it; + + cfix = arg; + if (!cfix) + return -pte_internal; + + for (it = 0; it < num_iterations; ++it) { + uint64_t offset, size, laddr; + int isid, errcode; + + offset = it % 7 < 4 ? 0x1000 : 0x2000; + size = it % 5 < 3 ? 0x1000 : 0x2000; + laddr = it % 3 < 2 ? 0x1000 : 0x2000; + + isid = pt_iscache_add_file(&cfix->iscache, "name", + offset, size, laddr); + if (isid < 0) + return isid; + + if (it % 11 < 9) + continue; + + errcode = pt_iscache_clear(&cfix->iscache); + if (errcode < 0) + return errcode; + } + + return 0; +} + +static struct ptunit_result stress(struct iscache_fixture *cfix, + int (*worker)(void *)) +{ + int errcode; + +#if defined(FEATURE_THREADS) + { + int thrd; + + for (thrd = 0; thrd < num_threads; ++thrd) + ptu_test(ptunit_thrd_create, &cfix->thrd, worker, cfix); + } +#endif /* defined(FEATURE_THREADS) */ + + errcode = worker(cfix); + ptu_int_eq(errcode, 0); + + return ptu_passed(); +} +int main(int argc, char **argv) +{ + struct iscache_fixture cfix, dfix, sfix; + struct ptunit_suite suite; + + cfix.init = cfix_init; + cfix.fini = cfix_fini; + + dfix.init = dfix_init; + dfix.fini = cfix_fini; + + sfix.init = sfix_init; + sfix.fini = cfix_fini; + + suite = ptunit_mk_suite(argc, argv); + + ptu_run(suite, init_null); + ptu_run(suite, fini_null); + ptu_run(suite, name_null); + ptu_run(suite, add_null); + ptu_run(suite, find_null); + ptu_run(suite, lookup_null); + ptu_run(suite, clear_null); + ptu_run(suite, free_null); + ptu_run(suite, add_file_null); + ptu_run(suite, read_null); + + ptu_run_f(suite, name, dfix); + ptu_run_f(suite, name_none, dfix); + + ptu_run_f(suite, init_fini, cfix); + ptu_run_f(suite, add, cfix); + ptu_run_f(suite, add_no_name, cfix); + ptu_run_f(suite, add_file, cfix); + + ptu_run_f(suite, find, cfix); + ptu_run_f(suite, find_empty, cfix); + ptu_run_f(suite, find_bad_filename, cfix); + ptu_run_f(suite, find_null_filename, cfix); + ptu_run_f(suite, find_bad_offset, cfix); + ptu_run_f(suite, find_bad_size, cfix); + ptu_run_f(suite, find_bad_laddr, cfix); + + ptu_run_f(suite, lookup, cfix); + ptu_run_f(suite, lookup_bad_isid, cfix); + + ptu_run_f(suite, clear_empty, cfix); + ptu_run_f(suite, clear_find, cfix); + ptu_run_f(suite, clear_lookup, cfix); + + ptu_run_f(suite, add_twice, cfix); + ptu_run_f(suite, add_same, cfix); + ptu_run_f(suite, add_twice_different_laddr, cfix); + ptu_run_f(suite, add_same_different_laddr, cfix); + ptu_run_f(suite, add_different_same_laddr, cfix); + + ptu_run_f(suite, add_file_same, cfix); + ptu_run_f(suite, add_file_same_different_laddr, cfix); + ptu_run_f(suite, add_file_different_same_laddr, cfix); + + ptu_run_f(suite, read, cfix); + ptu_run_f(suite, read_truncate, cfix); + ptu_run_f(suite, read_bad_vaddr, cfix); + ptu_run_f(suite, read_bad_isid, cfix); + + ptu_run_f(suite, lru_map, cfix); + ptu_run_f(suite, lru_read, cfix); + ptu_run_f(suite, lru_map_nodup, cfix); + ptu_run_f(suite, lru_map_too_big, cfix); + ptu_run_f(suite, lru_map_add_front, cfix); + ptu_run_f(suite, lru_map_move_front, cfix); + ptu_run_f(suite, lru_map_evict, cfix); + ptu_run_f(suite, lru_limit_evict, cfix); + ptu_run_f(suite, lru_bcache_evict, cfix); + ptu_run_f(suite, lru_bcache_clear, cfix); + ptu_run_f(suite, lru_clear, cfix); + + ptu_run_fp(suite, stress, cfix, worker_add); + ptu_run_fp(suite, stress, cfix, worker_add_file); + ptu_run_fp(suite, stress, sfix, worker_map); + ptu_run_fp(suite, stress, sfix, worker_map_limit); + ptu_run_fp(suite, stress, sfix, worker_map_bcache); + ptu_run_fp(suite, stress, cfix, worker_add_map); + ptu_run_fp(suite, stress, cfix, worker_add_clear); + ptu_run_fp(suite, stress, cfix, worker_add_file_map); + ptu_run_fp(suite, stress, cfix, worker_add_file_clear); + + return ptunit_report(&suite); +} |