FreeCalypso > hg > fc-magnetite
view src/cs/drivers/drv_app/ffs/board/tffs.c @ 354:cb3bc4fe730a
cfg-headers/voice-only: created
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 25 Dec 2017 00:32:10 +0000 |
parents | 945cf7f506b2 |
children |
line wrap: on
line source
/****************************************************************************** * 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); }