FreeCalypso > hg > fc-tourmaline
diff src/cs/drivers/drv_app/ffs/board/tffs.c @ 0:4e78acac3d88
src/{condat,cs,gpf,nucleus}: import from Selenite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 16 Oct 2020 06:23:26 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cs/drivers/drv_app/ffs/board/tffs.c Fri Oct 16 06:23:26 2020 +0000 @@ -0,0 +1,767 @@ + /****************************************************************************** + * Flash File System (ffs) + * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com + * + * ffs test scaffold/framework + * + * $Id: tffs.c 1.12.1.1.1.20 Fri, 19 Dec 2003 12:00:13 +0100 tsj $ + * + ******************************************************************************/ + +#ifndef TARGET +#include "ffs.cfg" +#endif + +#include "ffs/ffs.h" +#include "ffs/board/core.h" +#include "ffs/board/tffs.h" +#include "ffs/board/tdata.h" +#include "ffs/board/tmffs.h" +#include "ffs/board/ffstrace.h" + +#if (TARGET == 1) +#include "ffs/board/task.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> + + +/****************************************************************************** + * Prototypes and Globals + ******************************************************************************/ + +struct dir_s dir; +struct stat_s stat; +struct xstat_s xstat; + +int error; +#if (TARGET == 1) +int smallbuf_size = 512; +int bigbuf_size = 65536; + +#else +int smallbuf_size = 1024; +int bigbuf_size = 1024*1024*8; +#endif + +char *smallbuf = 0; +char *bigbuf = 0; + + +/****************************************************************************** + * Globals and Main + ******************************************************************************/ + +extern struct testcase_s testcase[]; + +struct test_s { + char *name; // name of currently executing test case + int numcases; // number of test cases run so far + int numcalls; // total number of ffs function calls so far + int numfails; // total number of failed test cases + int keepgoing; // keep going when a test case fails +} test; + +struct ffs_params_s param; + + +/****************************************************************************** + * Main Functions + ******************************************************************************/ + +effs_t ffs_initialize(void); +effs_t ffs_exit(void); + +// Each test case returns zero on success, non-zero on failure. +// test_execute() decides whether to continue with remaining test cases or +// not. + +#if (TARGET == 0) +void test_listall(void) +{ + struct testcase_s *p; + + printf("Test Cases:\n"); + for (p = testcase; p->name != 0; p++) { + printf("%8s: %s\n", p->name, p->comment); + } +} +#endif + +// <tests> is a comma-separated string of names of the test cases to +// run. Return number of test cases that failed. This is typically only 1, +// unless arg_keepgoing is set in which case it can be several. +int test_run(char *tests) +{ + struct testcase_s *ptc; + int i, failed, tparams[FFS_TESTCASE_PARAMS_MAX]; + struct this_test_s this; + char *pname, *testsnew; + + failed = 0; + + while (*tests != 0 && (failed == 0 || test.keepgoing)) + { + // Make local copy of test case name. We have to make local copies + // because we can be recursively called + pname = this.name; + while (isalpha(*tests) && *tests != 0 && *tests != ';') + *pname++ = *tests++; + *pname = 0; + + // Reset test case parameter(s) + for (i = 0; i < FFS_TESTCASE_PARAMS_MAX; i++) + tparams[i] = 0; + + // Collect parameter(s) for test case + i = 0; + while (isdigit(*tests)) { + tparams[i] = strtol(tests, &testsnew, 0); + if (tests == testsnew) + break; + tests = testsnew; + if (*tests == ',') + tests++; + i++; + if (i > FFS_TESTCASE_PARAMS_MAX) { + ttw(ttr(TTrTest, "TEST %s has TOO MANY PARAMS" NL, this.name)); + tw(tr(TR_FUNC, TrTest, "TEST %s TOO MANY PARAMS\n", this.name)); + return 1; + } + } + + if (*tests == ';') + tests++; + + // Lookup the test name in the array of test cases + for (ptc = testcase; ptc->name != 0; ptc++) { + if (strcmp(this.name, ptc->name) == 0) + break; + } + if (ptc->name == 0) { + ttw(ttr(TTrTest, "TEST %s UNKNOWN" NL, this.name)); + tw(tr(TR_FUNC, TrTest, "TEST %s UNKNOWN\n", this.name)); + return 1; + } + + this.numcalls = test.numcalls; + test_begin(this.name, tparams); + i = ptc->function(tparams[0], tparams[1]); + if (i != 0) { + failed++; + test_error(&this, test.numcalls); + } + test_end(&this, test.numcalls); + } + + return failed; +} + +// Overall test initialization. Read static ffs params with ffs_query() +void test_init(int keepgoing) +{ + test.numcases = 0; + test.numcalls = 0; + test.numfails = 0; + test.keepgoing = keepgoing; + + memset(¶m, 0, sizeof(struct ffs_params_s)); + + if (smallbuf == 0) { +#if (TARGET == 1) + smallbuf = (char*)target_malloc(smallbuf_size); +#else + smallbuf = malloc(smallbuf_size); +#endif + tw(tr(TR_FUNC, TrTest, "smallbuf = 0x%X, %d\n", + smallbuf, smallbuf_size)); + } + if (bigbuf == 0) { +#if (TARGET == 1) + // We continuously halve the buffer size until we succeed to allocate + // it. + while(1) { + if ((bigbuf = (char*)target_malloc(bigbuf_size)) != 0) + break; + bigbuf_size /= 2; + } +#else + bigbuf = malloc(bigbuf_size); +#endif + tw(tr(TR_FUNC, TrTest, "bigbuf = 0x%X, %d\n", bigbuf, bigbuf_size)); + } + + test_tdata_init(); + + tffs_initialize(); +} + +void test_exit(void) +{ + test_state_print(0); +} + + +// Begin new test case +void test_begin(char *name, int *params) +{ + test.numcases++; + + tw(tr(TR_BEGIN, TrTest, "TEST %s(%d,%d)\n", name, params[0], params[1])); + ttw(ttr(TTrTest, "TEST %s(%d,%d)" NL, name, params[0], params[1])); +} + +void test_end(struct this_test_s *test, int n) +{ + int objects = 0; + + ffs_query(Q_TOTAL_OBJECTS, (uint16 *) &objects); + tw(tr(TR_FUNC, TrTestHigh, "(total objects = %d)\n", objects)); + tw(tr(TR_END, TrTest, "")); + //tw(tr(TR_END, TrTest, "TEST END %s (calls = %d)\n", + // test->name, n - test->numcalls)); +} + +void test_error(struct this_test_s *test, int n) +{ + ttw(ttr(TTrTest, "TEST FAIL %s, call %d" NL, + test->name, n - test->numcalls)); + tw(tr(TR_FUNC, TrTest, "TEST FAIL %s, call %d\n", + test->name, n - test->numcalls)); +} + + +/****************************************************************************** + * Miscellaneous + ******************************************************************************/ + +int test_ffs_state_get(struct ffs_state_s *s) +{ + memset(s, 0, sizeof(struct ffs_state_s)); + + error = ffs_query(Q_INODES_USED, (uint16 *) &s->inodes_used); + error += ffs_query(Q_INODES_LOST, (uint16 *) &s->inodes_lost); + error += ffs_query(Q_OBJECTS_FREE, (uint16 *) &s->objects_free); + error += ffs_query(Q_TOTAL_OBJECTS, (uint16 *) &s->objects_total); + + error += ffs_query(Q_BYTES_USED, (uint16 *) &s->bytes_used); + error += ffs_query(Q_BYTES_LOST, (uint16 *) &s->bytes_lost); + error += ffs_query(Q_BYTES_FREE, (uint16 *) &s->bytes_free); + + error += ffs_query(Q_BLOCKS_FREE, (uint16 *) &s->blocks_free); + + return error; +} + +void test_ffs_state_copy(struct ffs_state_s *dst, struct ffs_state_s *src) +{ + memcpy(dst, src, sizeof(struct ffs_state_s)); +} + +void test_state_print(struct ffs_state_s *state) +{ + struct ffs_state_s mystate; + + if (state == 0) { + state = &mystate; + test_ffs_state_get(state); + } + + tw(tr(TR_FUNC, TrTest, "\nFFS State Summary:\n\n")); + ttw(str(TTrTest, NL "FFS State Summary:" NL NL)); + + tw(tr(TR_FUNC, TrTest, " block_size = %d\n", param.block_size)); + tw(tr(TR_FUNC, TrTest, " bytes_avail = %d\n\n", param.bytes_avail)); + + ttw(ttr(TTrTest, " block_size = %d" NL, param.block_size)); + ttw(ttr(TTrTest, " bytes_avail = %d" NL NL, param.bytes_avail)); + + test_state_bytes_print(state, 0); + test_state_objects_print(state, 0); + +} + +void test_state_objects_print(struct ffs_state_s *old, struct ffs_state_s *new) +{ + ttw(str(TTrTest, " inodes objects" NL)); + ttw(str(TTrTest, " -------------------------------------------" NL)); + ttw(str(TTrTest, " objects: used lost free total" NL)); + ttw(ttr(TTrTest, " old: %6d %6d %6d %6d" NL, + old->inodes_used, old->inodes_lost, + old->objects_free, old->objects_total)); + + tw(tr(TR_FUNC, TrTest, " inodes objects\n")); + tw(tr(TR_FUNC, TrTest, " -------------------------------------------\n")); + tw(tr(TR_FUNC, TrTest, " objects: used lost free total\n")); + tw(tr(TR_FUNC, TrTest, " old: %6d %6d %6d %6d\n", + old->inodes_used, old->inodes_lost, + old->objects_free, old->objects_total)); + + if (new != NULL) + { + ttw(ttr(TTrTest, + " new: %6d %6d %6d %6d" NL, + new->inodes_used, new->inodes_lost, + new->objects_free, new->objects_total)); + ttw(ttr(TTrTest, + " diff: %6d %6d %6d %6d" NL, + new->inodes_used - old->inodes_used, + new->inodes_lost - old->inodes_lost, + new->objects_free - old->objects_free, + new->objects_total - old->objects_total)); + + tw(tr(TR_FUNC, TrTest, + " new: %6d %6d %6d %6d\n", + new->inodes_used, new->inodes_lost, + new->objects_free, new->objects_total)); + tw(tr(TR_FUNC, TrTest, + " diff: %6d %6d %6d %6d\n", + new->inodes_used - old->inodes_used, + new->inodes_lost - old->inodes_lost, + new->objects_free - old->objects_free, + new->objects_total - old->objects_total)); + } + ttw(str(TTrTest, "" NL)); + tw(tr(TR_FUNC, TrTest, "\n")); +} + +void test_state_bytes_print(struct ffs_state_s *old, struct ffs_state_s *new) +{ + tw(tr(TR_FUNC, TrTest, " bytes: used lost free total\n")); + tw(tr(TR_FUNC, TrTest, " old: %8d %8d %8d %8d\n", + old->bytes_used, old->bytes_lost, + old->bytes_free, param.bytes_max)); + tw(tr(TR_FUNC, TrTest, " +/-: %8d %8d\n", + old->bytes_used - old->bytes_lost, + old->bytes_free + old->bytes_lost)); + + ttw(str(TTrTest, " bytes: used lost free total" NL)); + ttw(ttr(TTrTest, " old: %8d %8d %8d %8d" NL, + old->bytes_used, old->bytes_lost, + old->bytes_free, param.bytes_max)); + ttw(ttr(TTrTest, " +/-: %8d %8d" NL, + old->bytes_used - old->bytes_lost, + old->bytes_free + old->bytes_lost)); + + if (new != NULL) { + tw(tr(TR_FUNC, TrTest, " new: %8d %8d %8d\n", + new->bytes_used, new->bytes_lost, + new->bytes_free)); + tw(tr(TR_FUNC, TrTest, " diff: %8d %8d %8d\n", + new->bytes_used - old->bytes_used, + new->bytes_lost - old->bytes_lost, + new->bytes_free - old->bytes_free)); + + ttw(ttr(TTrTest, " new: %8d %8d %8d" NL, + new->bytes_used, new->bytes_lost, + new->bytes_free)); + ttw(ttr(TTrTest, " diff: %8d %8d %8d" NL, + new->bytes_used - old->bytes_used, + new->bytes_lost - old->bytes_lost, + new->bytes_free - old->bytes_free)); + } + tw(tr(TR_FUNC, TrTest, "\n")); + ttw(str(TTrTest, "" NL)); +} + + +// Retrieve all static ffs parameters with ffs_query() +int test_ffs_params_get(void) +{ + error = ffs_query(Q_FILENAME_MAX, ¶m.filename_max); + error += ffs_query(Q_PATH_DEPTH_MAX, ¶m.pathdepth_max); + error += ffs_query(Q_INODES_MAX, ¶m.inodes_max); + error += ffs_query(Q_BYTES_MAX, ¶m.bytes_max); + error += ffs_query(Q_DEV_BLOCKS, ¶m.numblocks); + error += ffs_query(Q_DEV_ATOMSIZE, ¶m.atomsize); + error += ffs_query(Q_BLOCKS_FREE_MIN, ¶m.blocks_free_min); + + // Compute block size + param.block_size = param.bytes_max / param.numblocks; + + // Compute total number of available storage space, subtracting + // fs.blocks_free_min plus one block for inodes + param.bytes_avail = + param.bytes_max - (param.block_size * (1 + param.blocks_free_min)); + + // Compute number of blocks available for data storage + param.data_blocks = param.numblocks - (1 + param.blocks_free_min); + + return error; +} + +void test_statistics_print(void) +{ + tw(tr(TR_FUNC, TrTest, "Data allocated(%dMB)\n", stats.data_allocated>>20)); + tw(tr(TR_FUNC, TrTest, "Reclaim candidates: most-lost(%d), most-unused(%d), youngest(%d)\n", stats.drec.most_lost, stats.drec.most_unused, stats.drec.youngest)); + + tw(tr(TR_FUNC, TrTest, "Data reclaimed: lost(%dMB), valid(%dMB)\n", + stats.drec.lost[0]>>20 , stats.drec.valid[0]>>20)); + + tw(tr(TR_FUNC, TrTest, "Inodes reclaimed: num(%d), valid(%d), lost(%d)\n", + stats.irec.num, stats.irec.valid, stats.irec.lost)); + + ttw(ttr(TTrTest, "Data allocated(%dMB)\n" NL, stats.data_allocated>>20)); + ttw(ttr(TTrTest, "Reclaim candidates: most-lost(%d), most-unused(%d), youngest(%d)\n" NL, stats.drec.most_lost, stats.drec.most_unused, stats.drec.youngest)); + + ttw(ttr(TTrTest, "Data reclaimed: lost(%dMB), valid(%dMB)\n" NL, + stats.drec.lost[0]>>20 , stats.drec.valid[0]>>20)); + + ttw(ttr(TTrTest, "Inodes reclaimed: num(%d), valid(%d), lost(%d)\n" NL, + stats.irec.num, stats.irec.valid, stats.irec.lost)); +} + +/****************************************************************************** + * Test and Expect Functions + ******************************************************************************/ + +int test_expect(int n, int xn) +{ + if (n == xn) + return 0; + + tw(tr(TR_FUNC, TrTest, + "ERROR: expect(%d,%d): got %d, '%s', expected %d, '%s'\n", + n, xn, n, ffs_strerror(n), xn, ffs_strerror(xn))); + ttw(ttr(TTrTest, "ERROR: expect(%d,%d)" NL, n, xn)); + + return -1; +} + +// Expect a return code >= 0 meaning EFFS_OK. +int test_expect_ok(int n) +{ + if (n >= 0) + return 0; + + tw(tr(TR_FUNC, TrTest, + "ERROR: expect_ok(%d) got %d, '%s', expected >= EFFS_OK\n", + n, ffs_strerror(n))); + ttw(ttr(TTrTest, "ERROR: expect_ok(%d)" NL, n)); + + return -1; +} + +int test_expect_equal(int n, int xn) +{ + if (n == xn) + return 0; + + tw(tr(TR_FUNC, TrTest, "ERROR: got %d, expected %d\n", n, xn)); + ttw(ttr(TTrTest, "ERROR: expect_eq(%d,%d" NL, n, xn)); + + return -1; +} + +int test_expect_not_equal(int n, int xn) +{ + if (n != xn) + return 0; + + tw(tr(TR_FUNC, TrTest, "ERROR: expect_ne(%d)\n", n)); + ttw(ttr(TTrTest, "ERROR: expect_ne(%d)" NL, n)); + + return -1; +} + +int test_expect_greater_than(int n, int xn) +{ + if (n > xn) + return 0; + + tw(tr(TR_FUNC, TrTest, "ERROR: expect_gt(%d,%d) got %d but expected > %d\n", + n, xn, n, xn)); + ttw(ttr(TTrTest, "ERROR: expect_gt(%d,%d)" NL, n, xn)); + + return -1; +} + +int test_expect_data(const void *data1, const void *data2, int size) +{ + if (memcmp(data1, data2, size) == 0) + return 0; + + tw(tr(TR_FUNC, TrTest, + "ERROR: expect_data(%d) got unexpected data\n", size)); + ttw(ttr(TTrTest, "ERROR: expect_data(%d)" NL, size)); + + return -1; +} + +// Check that contents of file with name <name> is the same as <data> of +// size <size>. +int test_expect_file(const char *name, const void *data, int size) +{ + test.numcalls++; + if (size > bigbuf_size) { + tw(tr(TR_FUNC, TrTest, "WARNING: expect_file(%d) buffer too small\n", + size)); + ttw(ttr(TTrTest, "WARNING: expect_file(%d) buffer too small" NL, size)); +#if (TARGET == 1) + return 0; +#endif + return -1; + } + + error = ffs_file_read(name, bigbuf, size); + if (test_expect_greater_than(error, EFFS_OK - 1)) + return -1; + return test_expect_data(bigbuf, data, size); +} + +int test_expect_state(struct ffs_state_s *old, struct ffs_state_s *new) +{ + int old_total, new_total; + + old_total = old->inodes_used - old->inodes_lost; + new_total = new->inodes_used - new->inodes_lost; + + if (old->objects_total == new->objects_total && + old->objects_total == new_total && + new->objects_total == old_total && + old->bytes_used == new->bytes_used && + old->bytes_lost == new->bytes_lost && + old->bytes_free == new->bytes_free) { + return 0; + } + + ttw(str(TTrTest, "ERROR: ffs state mismatch:" NL NL)); + tw(tr(TR_FUNC, TrTest, "ERROR: ffs state mismatch:\n\n")); + test_state_objects_print(old, new); + test_state_bytes_print(old, new); + + return -1; +} + +// Check if number of objects is unchanged +int test_expect_objects(struct ffs_state_s *old, struct ffs_state_s *new) +{ + int old_total, new_total; + + test_ffs_state_get(new); + + old_total = old->inodes_used - old->inodes_lost; + new_total = new->inodes_used - new->inodes_lost; + + if (old->objects_total == new->objects_total && + old->objects_total == new_total && + new->objects_total == old_total) { + return 0; + } + + ttw(ttr(TTrTest, "ERROR: expect_objects(%d, %d, %d, %d, %d, %d)" NL)); + tw(tr(TR_FUNC, TrTest, "ERROR: ffs state mismatch:\n\n")); + test_state_objects_print(old, new); + + return -1; +} + + +/****************************************************************************** + * FFS Functions + ******************************************************************************/ + +effs_t tffs_fcreate(const char *name, void *addr, int size) +{ + test.numcalls++; + return ffs_fcreate(name, addr, size); +} + +effs_t tffs_fupdate(const char *name, void *addr, int size) +{ + test.numcalls++; + return ffs_fupdate(name, addr, size); +} + +effs_t tffs_fwrite(const char *name, void *addr, int size) +{ + test.numcalls++; + return ffs_fwrite(name, addr, size); +} + +effs_t tffs_file_write(const char *name, void *addr, int size, uint16 option) +{ + test.numcalls++; + return ffs_file_write(name, addr, size, option); +} + +effs_t tffs_mkdir(const char *name) +{ + test.numcalls++; + return ffs_mkdir(name); +} + +effs_t tffs_symlink(const char *name, const char *actualpath) +{ + test.numcalls++; + return ffs_symlink(name, actualpath); +} + +effs_t tffs_remove(const char *name) +{ + test.numcalls++; + return ffs_remove(name); +} + +effs_t tffs_fcontrol(const char *name, int8 action, uint16 param) +{ + test.numcalls++; + return ffs_fcontrol(name, action, param); +} + +effs_t tffs_preformat(uint16 magic) +{ + test.numcalls++; + return ffs_preformat(magic); +} + +effs_t tffs_format(const char *name, uint16 magic) +{ + test.numcalls++; + return ffs_format(name, magic); +} + + +int tffs_fread(const char *name, void *addr, int size) +{ + test.numcalls++; + return ffs_file_read(name, addr, size); +} + +int tffs_file_read(const char *name, void *addr, int size) +{ + test.numcalls++; + return ffs_file_read(name, addr, size); +} + +int tffs_opendir(const char *name, struct dir_s *dir) +{ + test.numcalls++; + return ffs_opendir(name, dir); +} + +int tffs_readdir (struct dir_s *dir, char *name, int8 size) +{ + test.numcalls++; + return ffs_readdir(dir, name, size); +} + +int tffs_readlink(const char *name, char *addr, int size) +{ + test.numcalls++; + return ffs_readlink(name, addr, size); +} + +int tffs_rename(const char *oldname, const char *newname) +{ + test.numcalls++; + return ffs_rename(oldname, newname); +} + +effs_t tffs_stat(const char *name, struct stat_s *stat) +{ + test.numcalls++; + return ffs_stat(name, stat); +} + +effs_t tffs_fstat(fd_t fdi, struct stat_s *stat) +{ + test.numcalls++; + return ffs_fstat(fdi, stat); +} + +effs_t tffs_linkstat(const char *name, struct stat_s *stat) +{ + test.numcalls++; + return ffs_lstat(name, stat); +} + +effs_t tffs_lstat(const char *name, struct stat_s *stat) +{ + test.numcalls++; + return ffs_lstat(name, stat); +} + +effs_t tffs_xlstat(const char *name, struct xstat_s *stat) +{ + test.numcalls++; + return ffs_xlstat(name, stat); +} + +effs_t tffs_query(int8 query, void *p) +{ + return ffs_query(query, p); +} + + +effs_t tffs_initialize(void) +{ + effs_t myerror; + struct ffs_stats_s old_stats; + + test.numcalls++; + + memcpy(&old_stats, &stats, sizeof(struct ffs_stats_s)); + myerror = ffs_initialize(); + memcpy(&stats, &old_stats, sizeof(struct ffs_stats_s)); + + test_ffs_params_get(); + return myerror; +} + +effs_t tffs_exit(void) +{ + test.numcalls++; + return ffs_exit(); +} + +fd_t tffs_open(const char *pathname, ffs_options_t options) +{ + test.numcalls++; + return ffs_open(pathname, options); +} + +effs_t tffs_close(fd_t fdi) +{ + test.numcalls++; + return ffs_close(fdi); +} + +int tffs_write(fd_t fdi, void *addr, int size) +{ + test.numcalls++; + return ffs_write(fdi, addr, size); +} + +int tffs_read(fd_t fdi, void *addr, int size) +{ + test.numcalls++; + return ffs_read(fdi, addr, size); +} + +int tffs_seek(fd_t fdi, int offset, int whence) +{ + test.numcalls++; + return ffs_seek(fdi, offset, whence); +} + +effs_t tffs_truncate(const char *path, offset_t length) +{ + test.numcalls++; + return ffs_truncate(path, length); +} + +effs_t tffs_ftruncate(fd_t fdi, offset_t length) +{ + test.numcalls++; + return ffs_ftruncate(fdi, length); +} + +effs_t tffs_fdatasync(fd_t fdi) +{ + test.numcalls++; + return ffs_fdatasync(fdi); +}