119ea8026Sopenharmony_ci# test running a filesystem to exhaustion
219ea8026Sopenharmony_ci[cases.test_exhaustion_normal]
319ea8026Sopenharmony_cidefines.ERASE_CYCLES = 10
419ea8026Sopenharmony_cidefines.ERASE_COUNT = 256 # small bd so test runs faster
519ea8026Sopenharmony_cidefines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
619ea8026Sopenharmony_cidefines.BADBLOCK_BEHAVIOR = [
719ea8026Sopenharmony_ci    'LFS_EMUBD_BADBLOCK_PROGERROR',
819ea8026Sopenharmony_ci    'LFS_EMUBD_BADBLOCK_ERASEERROR',
919ea8026Sopenharmony_ci    'LFS_EMUBD_BADBLOCK_READERROR',
1019ea8026Sopenharmony_ci    'LFS_EMUBD_BADBLOCK_PROGNOOP',
1119ea8026Sopenharmony_ci    'LFS_EMUBD_BADBLOCK_ERASENOOP',
1219ea8026Sopenharmony_ci]
1319ea8026Sopenharmony_cidefines.FILES = 10
1419ea8026Sopenharmony_cicode = '''
1519ea8026Sopenharmony_ci    lfs_t lfs;
1619ea8026Sopenharmony_ci    lfs_format(&lfs, cfg) => 0;
1719ea8026Sopenharmony_ci    lfs_mount(&lfs, cfg) => 0;
1819ea8026Sopenharmony_ci    lfs_mkdir(&lfs, "roadrunner") => 0;
1919ea8026Sopenharmony_ci    lfs_unmount(&lfs) => 0;
2019ea8026Sopenharmony_ci
2119ea8026Sopenharmony_ci    uint32_t cycle = 0;
2219ea8026Sopenharmony_ci    while (true) {
2319ea8026Sopenharmony_ci        lfs_mount(&lfs, cfg) => 0;
2419ea8026Sopenharmony_ci        for (uint32_t i = 0; i < FILES; i++) {
2519ea8026Sopenharmony_ci            // chose name, roughly random seed, and random 2^n size
2619ea8026Sopenharmony_ci            char path[1024];
2719ea8026Sopenharmony_ci            sprintf(path, "roadrunner/test%d", i);
2819ea8026Sopenharmony_ci            uint32_t prng = cycle * i;
2919ea8026Sopenharmony_ci            lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
3019ea8026Sopenharmony_ci
3119ea8026Sopenharmony_ci            lfs_file_t file;
3219ea8026Sopenharmony_ci            lfs_file_open(&lfs, &file, path,
3319ea8026Sopenharmony_ci                    LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
3419ea8026Sopenharmony_ci
3519ea8026Sopenharmony_ci            for (lfs_size_t j = 0; j < size; j++) {
3619ea8026Sopenharmony_ci                char c = 'a' + (TEST_PRNG(&prng) % 26);
3719ea8026Sopenharmony_ci                lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
3819ea8026Sopenharmony_ci                assert(res == 1 || res == LFS_ERR_NOSPC);
3919ea8026Sopenharmony_ci                if (res == LFS_ERR_NOSPC) {
4019ea8026Sopenharmony_ci                    int err = lfs_file_close(&lfs, &file);
4119ea8026Sopenharmony_ci                    assert(err == 0 || err == LFS_ERR_NOSPC);
4219ea8026Sopenharmony_ci                    lfs_unmount(&lfs) => 0;
4319ea8026Sopenharmony_ci                    goto exhausted;
4419ea8026Sopenharmony_ci                }
4519ea8026Sopenharmony_ci            }
4619ea8026Sopenharmony_ci
4719ea8026Sopenharmony_ci            int err = lfs_file_close(&lfs, &file);
4819ea8026Sopenharmony_ci            assert(err == 0 || err == LFS_ERR_NOSPC);
4919ea8026Sopenharmony_ci            if (err == LFS_ERR_NOSPC) {
5019ea8026Sopenharmony_ci                lfs_unmount(&lfs) => 0;
5119ea8026Sopenharmony_ci                goto exhausted;
5219ea8026Sopenharmony_ci            }
5319ea8026Sopenharmony_ci        }
5419ea8026Sopenharmony_ci
5519ea8026Sopenharmony_ci        for (uint32_t i = 0; i < FILES; i++) {
5619ea8026Sopenharmony_ci            // check for errors
5719ea8026Sopenharmony_ci            char path[1024];
5819ea8026Sopenharmony_ci            sprintf(path, "roadrunner/test%d", i);
5919ea8026Sopenharmony_ci            uint32_t prng = cycle * i;
6019ea8026Sopenharmony_ci            lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
6119ea8026Sopenharmony_ci
6219ea8026Sopenharmony_ci            lfs_file_t file;
6319ea8026Sopenharmony_ci            lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
6419ea8026Sopenharmony_ci            for (lfs_size_t j = 0; j < size; j++) {
6519ea8026Sopenharmony_ci                char c = 'a' + (TEST_PRNG(&prng) % 26);
6619ea8026Sopenharmony_ci                char r;
6719ea8026Sopenharmony_ci                lfs_file_read(&lfs, &file, &r, 1) => 1;
6819ea8026Sopenharmony_ci                assert(r == c);
6919ea8026Sopenharmony_ci            }
7019ea8026Sopenharmony_ci
7119ea8026Sopenharmony_ci            lfs_file_close(&lfs, &file) => 0;
7219ea8026Sopenharmony_ci        }
7319ea8026Sopenharmony_ci        lfs_unmount(&lfs) => 0;
7419ea8026Sopenharmony_ci
7519ea8026Sopenharmony_ci        cycle += 1;
7619ea8026Sopenharmony_ci    }
7719ea8026Sopenharmony_ci
7819ea8026Sopenharmony_ciexhausted:
7919ea8026Sopenharmony_ci    // should still be readable
8019ea8026Sopenharmony_ci    lfs_mount(&lfs, cfg) => 0;
8119ea8026Sopenharmony_ci    for (uint32_t i = 0; i < FILES; i++) {
8219ea8026Sopenharmony_ci        // check for errors
8319ea8026Sopenharmony_ci        char path[1024];
8419ea8026Sopenharmony_ci        sprintf(path, "roadrunner/test%d", i);
8519ea8026Sopenharmony_ci        struct lfs_info info;
8619ea8026Sopenharmony_ci        lfs_stat(&lfs, path, &info) => 0;
8719ea8026Sopenharmony_ci    }
8819ea8026Sopenharmony_ci    lfs_unmount(&lfs) => 0;
8919ea8026Sopenharmony_ci
9019ea8026Sopenharmony_ci    LFS_WARN("completed %d cycles", cycle);
9119ea8026Sopenharmony_ci'''
9219ea8026Sopenharmony_ci
9319ea8026Sopenharmony_ci# test running a filesystem to exhaustion
9419ea8026Sopenharmony_ci# which also requires expanding superblocks
9519ea8026Sopenharmony_ci[cases.test_exhaustion_superblocks]
9619ea8026Sopenharmony_cidefines.ERASE_CYCLES = 10
9719ea8026Sopenharmony_cidefines.ERASE_COUNT = 256 # small bd so test runs faster
9819ea8026Sopenharmony_cidefines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
9919ea8026Sopenharmony_cidefines.BADBLOCK_BEHAVIOR = [
10019ea8026Sopenharmony_ci    'LFS_EMUBD_BADBLOCK_PROGERROR',
10119ea8026Sopenharmony_ci    'LFS_EMUBD_BADBLOCK_ERASEERROR',
10219ea8026Sopenharmony_ci    'LFS_EMUBD_BADBLOCK_READERROR',
10319ea8026Sopenharmony_ci    'LFS_EMUBD_BADBLOCK_PROGNOOP',
10419ea8026Sopenharmony_ci    'LFS_EMUBD_BADBLOCK_ERASENOOP',
10519ea8026Sopenharmony_ci]
10619ea8026Sopenharmony_cidefines.FILES = 10
10719ea8026Sopenharmony_cicode = '''
10819ea8026Sopenharmony_ci    lfs_t lfs;
10919ea8026Sopenharmony_ci    lfs_format(&lfs, cfg) => 0;
11019ea8026Sopenharmony_ci
11119ea8026Sopenharmony_ci    uint32_t cycle = 0;
11219ea8026Sopenharmony_ci    while (true) {
11319ea8026Sopenharmony_ci        lfs_mount(&lfs, cfg) => 0;
11419ea8026Sopenharmony_ci        for (uint32_t i = 0; i < FILES; i++) {
11519ea8026Sopenharmony_ci            // chose name, roughly random seed, and random 2^n size
11619ea8026Sopenharmony_ci            char path[1024];
11719ea8026Sopenharmony_ci            sprintf(path, "test%d", i);
11819ea8026Sopenharmony_ci            uint32_t prng = cycle * i;
11919ea8026Sopenharmony_ci            lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
12019ea8026Sopenharmony_ci
12119ea8026Sopenharmony_ci            lfs_file_t file;
12219ea8026Sopenharmony_ci            lfs_file_open(&lfs, &file, path,
12319ea8026Sopenharmony_ci                    LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
12419ea8026Sopenharmony_ci
12519ea8026Sopenharmony_ci            for (lfs_size_t j = 0; j < size; j++) {
12619ea8026Sopenharmony_ci                char c = 'a' + (TEST_PRNG(&prng) % 26);
12719ea8026Sopenharmony_ci                lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
12819ea8026Sopenharmony_ci                assert(res == 1 || res == LFS_ERR_NOSPC);
12919ea8026Sopenharmony_ci                if (res == LFS_ERR_NOSPC) {
13019ea8026Sopenharmony_ci                    int err = lfs_file_close(&lfs, &file);
13119ea8026Sopenharmony_ci                    assert(err == 0 || err == LFS_ERR_NOSPC);
13219ea8026Sopenharmony_ci                    lfs_unmount(&lfs) => 0;
13319ea8026Sopenharmony_ci                    goto exhausted;
13419ea8026Sopenharmony_ci                }
13519ea8026Sopenharmony_ci            }
13619ea8026Sopenharmony_ci
13719ea8026Sopenharmony_ci            int err = lfs_file_close(&lfs, &file);
13819ea8026Sopenharmony_ci            assert(err == 0 || err == LFS_ERR_NOSPC);
13919ea8026Sopenharmony_ci            if (err == LFS_ERR_NOSPC) {
14019ea8026Sopenharmony_ci                lfs_unmount(&lfs) => 0;
14119ea8026Sopenharmony_ci                goto exhausted;
14219ea8026Sopenharmony_ci            }
14319ea8026Sopenharmony_ci        }
14419ea8026Sopenharmony_ci
14519ea8026Sopenharmony_ci        for (uint32_t i = 0; i < FILES; i++) {
14619ea8026Sopenharmony_ci            // check for errors
14719ea8026Sopenharmony_ci            char path[1024];
14819ea8026Sopenharmony_ci            sprintf(path, "test%d", i);
14919ea8026Sopenharmony_ci            uint32_t prng = cycle * i;
15019ea8026Sopenharmony_ci            lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
15119ea8026Sopenharmony_ci
15219ea8026Sopenharmony_ci            lfs_file_t file;
15319ea8026Sopenharmony_ci            lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
15419ea8026Sopenharmony_ci            for (lfs_size_t j = 0; j < size; j++) {
15519ea8026Sopenharmony_ci                char c = 'a' + (TEST_PRNG(&prng) % 26);
15619ea8026Sopenharmony_ci                char r;
15719ea8026Sopenharmony_ci                lfs_file_read(&lfs, &file, &r, 1) => 1;
15819ea8026Sopenharmony_ci                assert(r == c);
15919ea8026Sopenharmony_ci            }
16019ea8026Sopenharmony_ci
16119ea8026Sopenharmony_ci            lfs_file_close(&lfs, &file) => 0;
16219ea8026Sopenharmony_ci        }
16319ea8026Sopenharmony_ci        lfs_unmount(&lfs) => 0;
16419ea8026Sopenharmony_ci
16519ea8026Sopenharmony_ci        cycle += 1;
16619ea8026Sopenharmony_ci    }
16719ea8026Sopenharmony_ci
16819ea8026Sopenharmony_ciexhausted:
16919ea8026Sopenharmony_ci    // should still be readable
17019ea8026Sopenharmony_ci    lfs_mount(&lfs, cfg) => 0;
17119ea8026Sopenharmony_ci    for (uint32_t i = 0; i < FILES; i++) {
17219ea8026Sopenharmony_ci        // check for errors
17319ea8026Sopenharmony_ci        char path[1024];
17419ea8026Sopenharmony_ci        struct lfs_info info;
17519ea8026Sopenharmony_ci        sprintf(path, "test%d", i);
17619ea8026Sopenharmony_ci        lfs_stat(&lfs, path, &info) => 0;
17719ea8026Sopenharmony_ci    }
17819ea8026Sopenharmony_ci    lfs_unmount(&lfs) => 0;
17919ea8026Sopenharmony_ci
18019ea8026Sopenharmony_ci    LFS_WARN("completed %d cycles", cycle);
18119ea8026Sopenharmony_ci'''
18219ea8026Sopenharmony_ci
18319ea8026Sopenharmony_ci# These are a sort of high-level litmus test for wear-leveling. One definition
18419ea8026Sopenharmony_ci# of wear-leveling is that increasing a block device's space translates directly
18519ea8026Sopenharmony_ci# into increasing the block devices lifetime. This is something we can actually
18619ea8026Sopenharmony_ci# check for.
18719ea8026Sopenharmony_ci
18819ea8026Sopenharmony_ci# wear-level test running a filesystem to exhaustion
18919ea8026Sopenharmony_ci[cases.test_exhuastion_wear_leveling]
19019ea8026Sopenharmony_cidefines.ERASE_CYCLES = 20
19119ea8026Sopenharmony_cidefines.ERASE_COUNT = 256 # small bd so test runs faster
19219ea8026Sopenharmony_cidefines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
19319ea8026Sopenharmony_cidefines.FILES = 10
19419ea8026Sopenharmony_cicode = '''
19519ea8026Sopenharmony_ci    uint32_t run_cycles[2];
19619ea8026Sopenharmony_ci    const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT};
19719ea8026Sopenharmony_ci
19819ea8026Sopenharmony_ci    for (int run = 0; run < 2; run++) {
19919ea8026Sopenharmony_ci        for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) {
20019ea8026Sopenharmony_ci            lfs_emubd_setwear(cfg, b,
20119ea8026Sopenharmony_ci                    (b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0;
20219ea8026Sopenharmony_ci        }
20319ea8026Sopenharmony_ci
20419ea8026Sopenharmony_ci        lfs_t lfs;
20519ea8026Sopenharmony_ci        lfs_format(&lfs, cfg) => 0;
20619ea8026Sopenharmony_ci        lfs_mount(&lfs, cfg) => 0;
20719ea8026Sopenharmony_ci        lfs_mkdir(&lfs, "roadrunner") => 0;
20819ea8026Sopenharmony_ci        lfs_unmount(&lfs) => 0;
20919ea8026Sopenharmony_ci
21019ea8026Sopenharmony_ci        uint32_t cycle = 0;
21119ea8026Sopenharmony_ci        while (true) {
21219ea8026Sopenharmony_ci            lfs_mount(&lfs, cfg) => 0;
21319ea8026Sopenharmony_ci            for (uint32_t i = 0; i < FILES; i++) {
21419ea8026Sopenharmony_ci                // chose name, roughly random seed, and random 2^n size
21519ea8026Sopenharmony_ci                char path[1024];
21619ea8026Sopenharmony_ci                sprintf(path, "roadrunner/test%d", i);
21719ea8026Sopenharmony_ci                uint32_t prng = cycle * i;
21819ea8026Sopenharmony_ci                lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
21919ea8026Sopenharmony_ci
22019ea8026Sopenharmony_ci                lfs_file_t file;
22119ea8026Sopenharmony_ci                lfs_file_open(&lfs, &file, path,
22219ea8026Sopenharmony_ci                        LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
22319ea8026Sopenharmony_ci
22419ea8026Sopenharmony_ci                for (lfs_size_t j = 0; j < size; j++) {
22519ea8026Sopenharmony_ci                    char c = 'a' + (TEST_PRNG(&prng) % 26);
22619ea8026Sopenharmony_ci                    lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
22719ea8026Sopenharmony_ci                    assert(res == 1 || res == LFS_ERR_NOSPC);
22819ea8026Sopenharmony_ci                    if (res == LFS_ERR_NOSPC) {
22919ea8026Sopenharmony_ci                        int err = lfs_file_close(&lfs, &file);
23019ea8026Sopenharmony_ci                        assert(err == 0 || err == LFS_ERR_NOSPC);
23119ea8026Sopenharmony_ci                        lfs_unmount(&lfs) => 0;
23219ea8026Sopenharmony_ci                        goto exhausted;
23319ea8026Sopenharmony_ci                    }
23419ea8026Sopenharmony_ci                }
23519ea8026Sopenharmony_ci
23619ea8026Sopenharmony_ci                int err = lfs_file_close(&lfs, &file);
23719ea8026Sopenharmony_ci                assert(err == 0 || err == LFS_ERR_NOSPC);
23819ea8026Sopenharmony_ci                if (err == LFS_ERR_NOSPC) {
23919ea8026Sopenharmony_ci                    lfs_unmount(&lfs) => 0;
24019ea8026Sopenharmony_ci                    goto exhausted;
24119ea8026Sopenharmony_ci                }
24219ea8026Sopenharmony_ci            }
24319ea8026Sopenharmony_ci
24419ea8026Sopenharmony_ci            for (uint32_t i = 0; i < FILES; i++) {
24519ea8026Sopenharmony_ci                // check for errors
24619ea8026Sopenharmony_ci                char path[1024];
24719ea8026Sopenharmony_ci                sprintf(path, "roadrunner/test%d", i);
24819ea8026Sopenharmony_ci                uint32_t prng = cycle * i;
24919ea8026Sopenharmony_ci                lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
25019ea8026Sopenharmony_ci
25119ea8026Sopenharmony_ci                lfs_file_t file;
25219ea8026Sopenharmony_ci                lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
25319ea8026Sopenharmony_ci                for (lfs_size_t j = 0; j < size; j++) {
25419ea8026Sopenharmony_ci                    char c = 'a' + (TEST_PRNG(&prng) % 26);
25519ea8026Sopenharmony_ci                    char r;
25619ea8026Sopenharmony_ci                    lfs_file_read(&lfs, &file, &r, 1) => 1;
25719ea8026Sopenharmony_ci                    assert(r == c);
25819ea8026Sopenharmony_ci                }
25919ea8026Sopenharmony_ci
26019ea8026Sopenharmony_ci                lfs_file_close(&lfs, &file) => 0;
26119ea8026Sopenharmony_ci            }
26219ea8026Sopenharmony_ci            lfs_unmount(&lfs) => 0;
26319ea8026Sopenharmony_ci
26419ea8026Sopenharmony_ci            cycle += 1;
26519ea8026Sopenharmony_ci        }
26619ea8026Sopenharmony_ci
26719ea8026Sopenharmony_ciexhausted:
26819ea8026Sopenharmony_ci        // should still be readable
26919ea8026Sopenharmony_ci        lfs_mount(&lfs, cfg) => 0;
27019ea8026Sopenharmony_ci        for (uint32_t i = 0; i < FILES; i++) {
27119ea8026Sopenharmony_ci            // check for errors
27219ea8026Sopenharmony_ci            char path[1024];
27319ea8026Sopenharmony_ci            struct lfs_info info;
27419ea8026Sopenharmony_ci            sprintf(path, "roadrunner/test%d", i);
27519ea8026Sopenharmony_ci            lfs_stat(&lfs, path, &info) => 0;
27619ea8026Sopenharmony_ci        }
27719ea8026Sopenharmony_ci        lfs_unmount(&lfs) => 0;
27819ea8026Sopenharmony_ci
27919ea8026Sopenharmony_ci        run_cycles[run] = cycle;
28019ea8026Sopenharmony_ci        LFS_WARN("completed %d blocks %d cycles",
28119ea8026Sopenharmony_ci                run_block_count[run], run_cycles[run]);
28219ea8026Sopenharmony_ci    }
28319ea8026Sopenharmony_ci
28419ea8026Sopenharmony_ci    // check we increased the lifetime by 2x with ~10% error
28519ea8026Sopenharmony_ci    LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
28619ea8026Sopenharmony_ci'''
28719ea8026Sopenharmony_ci
28819ea8026Sopenharmony_ci# wear-level test + expanding superblock
28919ea8026Sopenharmony_ci[cases.test_exhaustion_wear_leveling_superblocks]
29019ea8026Sopenharmony_cidefines.ERASE_CYCLES = 20
29119ea8026Sopenharmony_cidefines.ERASE_COUNT = 256 # small bd so test runs faster
29219ea8026Sopenharmony_cidefines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
29319ea8026Sopenharmony_cidefines.FILES = 10
29419ea8026Sopenharmony_cicode = '''
29519ea8026Sopenharmony_ci    uint32_t run_cycles[2];
29619ea8026Sopenharmony_ci    const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT};
29719ea8026Sopenharmony_ci
29819ea8026Sopenharmony_ci    for (int run = 0; run < 2; run++) {
29919ea8026Sopenharmony_ci        for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) {
30019ea8026Sopenharmony_ci            lfs_emubd_setwear(cfg, b,
30119ea8026Sopenharmony_ci                    (b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0;
30219ea8026Sopenharmony_ci        }
30319ea8026Sopenharmony_ci
30419ea8026Sopenharmony_ci        lfs_t lfs;
30519ea8026Sopenharmony_ci        lfs_format(&lfs, cfg) => 0;
30619ea8026Sopenharmony_ci
30719ea8026Sopenharmony_ci        uint32_t cycle = 0;
30819ea8026Sopenharmony_ci        while (true) {
30919ea8026Sopenharmony_ci            lfs_mount(&lfs, cfg) => 0;
31019ea8026Sopenharmony_ci            for (uint32_t i = 0; i < FILES; i++) {
31119ea8026Sopenharmony_ci                // chose name, roughly random seed, and random 2^n size
31219ea8026Sopenharmony_ci                char path[1024];
31319ea8026Sopenharmony_ci                sprintf(path, "test%d", i);
31419ea8026Sopenharmony_ci                uint32_t prng = cycle * i;
31519ea8026Sopenharmony_ci                lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
31619ea8026Sopenharmony_ci
31719ea8026Sopenharmony_ci                lfs_file_t file;
31819ea8026Sopenharmony_ci                lfs_file_open(&lfs, &file, path,
31919ea8026Sopenharmony_ci                        LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
32019ea8026Sopenharmony_ci
32119ea8026Sopenharmony_ci                for (lfs_size_t j = 0; j < size; j++) {
32219ea8026Sopenharmony_ci                    char c = 'a' + (TEST_PRNG(&prng) % 26);
32319ea8026Sopenharmony_ci                    lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
32419ea8026Sopenharmony_ci                    assert(res == 1 || res == LFS_ERR_NOSPC);
32519ea8026Sopenharmony_ci                    if (res == LFS_ERR_NOSPC) {
32619ea8026Sopenharmony_ci                        int err = lfs_file_close(&lfs, &file);
32719ea8026Sopenharmony_ci                        assert(err == 0 || err == LFS_ERR_NOSPC);
32819ea8026Sopenharmony_ci                        lfs_unmount(&lfs) => 0;
32919ea8026Sopenharmony_ci                        goto exhausted;
33019ea8026Sopenharmony_ci                    }
33119ea8026Sopenharmony_ci                }
33219ea8026Sopenharmony_ci
33319ea8026Sopenharmony_ci                int err = lfs_file_close(&lfs, &file);
33419ea8026Sopenharmony_ci                assert(err == 0 || err == LFS_ERR_NOSPC);
33519ea8026Sopenharmony_ci                if (err == LFS_ERR_NOSPC) {
33619ea8026Sopenharmony_ci                    lfs_unmount(&lfs) => 0;
33719ea8026Sopenharmony_ci                    goto exhausted;
33819ea8026Sopenharmony_ci                }
33919ea8026Sopenharmony_ci            }
34019ea8026Sopenharmony_ci
34119ea8026Sopenharmony_ci            for (uint32_t i = 0; i < FILES; i++) {
34219ea8026Sopenharmony_ci                // check for errors
34319ea8026Sopenharmony_ci                char path[1024];
34419ea8026Sopenharmony_ci                sprintf(path, "test%d", i);
34519ea8026Sopenharmony_ci                uint32_t prng = cycle * i;
34619ea8026Sopenharmony_ci                lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
34719ea8026Sopenharmony_ci
34819ea8026Sopenharmony_ci                lfs_file_t file;
34919ea8026Sopenharmony_ci                lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
35019ea8026Sopenharmony_ci                for (lfs_size_t j = 0; j < size; j++) {
35119ea8026Sopenharmony_ci                    char c = 'a' + (TEST_PRNG(&prng) % 26);
35219ea8026Sopenharmony_ci                    char r;
35319ea8026Sopenharmony_ci                    lfs_file_read(&lfs, &file, &r, 1) => 1;
35419ea8026Sopenharmony_ci                    assert(r == c);
35519ea8026Sopenharmony_ci                }
35619ea8026Sopenharmony_ci
35719ea8026Sopenharmony_ci                lfs_file_close(&lfs, &file) => 0;
35819ea8026Sopenharmony_ci            }
35919ea8026Sopenharmony_ci            lfs_unmount(&lfs) => 0;
36019ea8026Sopenharmony_ci
36119ea8026Sopenharmony_ci            cycle += 1;
36219ea8026Sopenharmony_ci        }
36319ea8026Sopenharmony_ci
36419ea8026Sopenharmony_ciexhausted:
36519ea8026Sopenharmony_ci        // should still be readable
36619ea8026Sopenharmony_ci        lfs_mount(&lfs, cfg) => 0;
36719ea8026Sopenharmony_ci        for (uint32_t i = 0; i < FILES; i++) {
36819ea8026Sopenharmony_ci            // check for errors
36919ea8026Sopenharmony_ci            char path[1024];
37019ea8026Sopenharmony_ci            struct lfs_info info;
37119ea8026Sopenharmony_ci            sprintf(path, "test%d", i);
37219ea8026Sopenharmony_ci            lfs_stat(&lfs, path, &info) => 0;
37319ea8026Sopenharmony_ci        }
37419ea8026Sopenharmony_ci        lfs_unmount(&lfs) => 0;
37519ea8026Sopenharmony_ci
37619ea8026Sopenharmony_ci        run_cycles[run] = cycle;
37719ea8026Sopenharmony_ci        LFS_WARN("completed %d blocks %d cycles",
37819ea8026Sopenharmony_ci                run_block_count[run], run_cycles[run]);
37919ea8026Sopenharmony_ci    }
38019ea8026Sopenharmony_ci
38119ea8026Sopenharmony_ci    // check we increased the lifetime by 2x with ~10% error
38219ea8026Sopenharmony_ci    LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
38319ea8026Sopenharmony_ci'''
38419ea8026Sopenharmony_ci
38519ea8026Sopenharmony_ci# test that we wear blocks roughly evenly
38619ea8026Sopenharmony_ci[cases.test_exhaustion_wear_distribution]
38719ea8026Sopenharmony_cidefines.ERASE_CYCLES = 0xffffffff
38819ea8026Sopenharmony_cidefines.ERASE_COUNT = 256 # small bd so test runs faster
38919ea8026Sopenharmony_cidefines.BLOCK_CYCLES = [5, 4, 3, 2, 1]
39019ea8026Sopenharmony_cidefines.CYCLES = 100
39119ea8026Sopenharmony_cidefines.FILES = 10
39219ea8026Sopenharmony_ciif = 'BLOCK_CYCLES < CYCLES/10'
39319ea8026Sopenharmony_cicode = '''
39419ea8026Sopenharmony_ci    lfs_t lfs;
39519ea8026Sopenharmony_ci    lfs_format(&lfs, cfg) => 0;
39619ea8026Sopenharmony_ci    lfs_mount(&lfs, cfg) => 0;
39719ea8026Sopenharmony_ci    lfs_mkdir(&lfs, "roadrunner") => 0;
39819ea8026Sopenharmony_ci    lfs_unmount(&lfs) => 0;
39919ea8026Sopenharmony_ci
40019ea8026Sopenharmony_ci    uint32_t cycle = 0;
40119ea8026Sopenharmony_ci    while (cycle < CYCLES) {
40219ea8026Sopenharmony_ci        lfs_mount(&lfs, cfg) => 0;
40319ea8026Sopenharmony_ci        for (uint32_t i = 0; i < FILES; i++) {
40419ea8026Sopenharmony_ci            // chose name, roughly random seed, and random 2^n size
40519ea8026Sopenharmony_ci            char path[1024];
40619ea8026Sopenharmony_ci            sprintf(path, "roadrunner/test%d", i);
40719ea8026Sopenharmony_ci            uint32_t prng = cycle * i;
40819ea8026Sopenharmony_ci            lfs_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2);
40919ea8026Sopenharmony_ci
41019ea8026Sopenharmony_ci            lfs_file_t file;
41119ea8026Sopenharmony_ci            lfs_file_open(&lfs, &file, path,
41219ea8026Sopenharmony_ci                    LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
41319ea8026Sopenharmony_ci
41419ea8026Sopenharmony_ci            for (lfs_size_t j = 0; j < size; j++) {
41519ea8026Sopenharmony_ci                char c = 'a' + (TEST_PRNG(&prng) % 26);
41619ea8026Sopenharmony_ci                lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
41719ea8026Sopenharmony_ci                assert(res == 1 || res == LFS_ERR_NOSPC);
41819ea8026Sopenharmony_ci                if (res == LFS_ERR_NOSPC) {
41919ea8026Sopenharmony_ci                    int err = lfs_file_close(&lfs, &file);
42019ea8026Sopenharmony_ci                    assert(err == 0 || err == LFS_ERR_NOSPC);
42119ea8026Sopenharmony_ci                    lfs_unmount(&lfs) => 0;
42219ea8026Sopenharmony_ci                    goto exhausted;
42319ea8026Sopenharmony_ci                }
42419ea8026Sopenharmony_ci            }
42519ea8026Sopenharmony_ci
42619ea8026Sopenharmony_ci            int err = lfs_file_close(&lfs, &file);
42719ea8026Sopenharmony_ci            assert(err == 0 || err == LFS_ERR_NOSPC);
42819ea8026Sopenharmony_ci            if (err == LFS_ERR_NOSPC) {
42919ea8026Sopenharmony_ci                lfs_unmount(&lfs) => 0;
43019ea8026Sopenharmony_ci                goto exhausted;
43119ea8026Sopenharmony_ci            }
43219ea8026Sopenharmony_ci        }
43319ea8026Sopenharmony_ci
43419ea8026Sopenharmony_ci        for (uint32_t i = 0; i < FILES; i++) {
43519ea8026Sopenharmony_ci            // check for errors
43619ea8026Sopenharmony_ci            char path[1024];
43719ea8026Sopenharmony_ci            sprintf(path, "roadrunner/test%d", i);
43819ea8026Sopenharmony_ci            uint32_t prng = cycle * i;
43919ea8026Sopenharmony_ci            lfs_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2);
44019ea8026Sopenharmony_ci
44119ea8026Sopenharmony_ci            lfs_file_t file;
44219ea8026Sopenharmony_ci            lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
44319ea8026Sopenharmony_ci            for (lfs_size_t j = 0; j < size; j++) {
44419ea8026Sopenharmony_ci                char c = 'a' + (TEST_PRNG(&prng) % 26);
44519ea8026Sopenharmony_ci                char r;
44619ea8026Sopenharmony_ci                lfs_file_read(&lfs, &file, &r, 1) => 1;
44719ea8026Sopenharmony_ci                assert(r == c);
44819ea8026Sopenharmony_ci            }
44919ea8026Sopenharmony_ci
45019ea8026Sopenharmony_ci            lfs_file_close(&lfs, &file) => 0;
45119ea8026Sopenharmony_ci        }
45219ea8026Sopenharmony_ci        lfs_unmount(&lfs) => 0;
45319ea8026Sopenharmony_ci
45419ea8026Sopenharmony_ci        cycle += 1;
45519ea8026Sopenharmony_ci    }
45619ea8026Sopenharmony_ci
45719ea8026Sopenharmony_ciexhausted:
45819ea8026Sopenharmony_ci    // should still be readable
45919ea8026Sopenharmony_ci    lfs_mount(&lfs, cfg) => 0;
46019ea8026Sopenharmony_ci    for (uint32_t i = 0; i < FILES; i++) {
46119ea8026Sopenharmony_ci        // check for errors
46219ea8026Sopenharmony_ci        char path[1024];
46319ea8026Sopenharmony_ci        struct lfs_info info;
46419ea8026Sopenharmony_ci        sprintf(path, "roadrunner/test%d", i);
46519ea8026Sopenharmony_ci        lfs_stat(&lfs, path, &info) => 0;
46619ea8026Sopenharmony_ci    }
46719ea8026Sopenharmony_ci    lfs_unmount(&lfs) => 0;
46819ea8026Sopenharmony_ci
46919ea8026Sopenharmony_ci    LFS_WARN("completed %d cycles", cycle);
47019ea8026Sopenharmony_ci
47119ea8026Sopenharmony_ci    // check the wear on our block device
47219ea8026Sopenharmony_ci    lfs_emubd_wear_t minwear = -1;
47319ea8026Sopenharmony_ci    lfs_emubd_wear_t totalwear = 0;
47419ea8026Sopenharmony_ci    lfs_emubd_wear_t maxwear = 0;
47519ea8026Sopenharmony_ci    // skip 0 and 1 as superblock movement is intentionally avoided
47619ea8026Sopenharmony_ci    for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) {
47719ea8026Sopenharmony_ci        lfs_emubd_wear_t wear = lfs_emubd_wear(cfg, b);
47819ea8026Sopenharmony_ci        printf("%08x: wear %d\n", b, wear);
47919ea8026Sopenharmony_ci        assert(wear >= 0);
48019ea8026Sopenharmony_ci        if (wear < minwear) {
48119ea8026Sopenharmony_ci            minwear = wear;
48219ea8026Sopenharmony_ci        }
48319ea8026Sopenharmony_ci        if (wear > maxwear) {
48419ea8026Sopenharmony_ci            maxwear = wear;
48519ea8026Sopenharmony_ci        }
48619ea8026Sopenharmony_ci        totalwear += wear;
48719ea8026Sopenharmony_ci    }
48819ea8026Sopenharmony_ci    lfs_emubd_wear_t avgwear = totalwear / BLOCK_COUNT;
48919ea8026Sopenharmony_ci    LFS_WARN("max wear: %d cycles", maxwear);
49019ea8026Sopenharmony_ci    LFS_WARN("avg wear: %d cycles", totalwear / (int)BLOCK_COUNT);
49119ea8026Sopenharmony_ci    LFS_WARN("min wear: %d cycles", minwear);
49219ea8026Sopenharmony_ci
49319ea8026Sopenharmony_ci    // find standard deviation^2
49419ea8026Sopenharmony_ci    lfs_emubd_wear_t dev2 = 0;
49519ea8026Sopenharmony_ci    for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) {
49619ea8026Sopenharmony_ci        lfs_emubd_wear_t wear = lfs_emubd_wear(cfg, b);
49719ea8026Sopenharmony_ci        assert(wear >= 0);
49819ea8026Sopenharmony_ci        lfs_emubd_swear_t diff = wear - avgwear;
49919ea8026Sopenharmony_ci        dev2 += diff*diff;
50019ea8026Sopenharmony_ci    }
50119ea8026Sopenharmony_ci    dev2 /= totalwear;
50219ea8026Sopenharmony_ci    LFS_WARN("std dev^2: %d", dev2);
50319ea8026Sopenharmony_ci    assert(dev2 < 8);
50419ea8026Sopenharmony_ci'''
50519ea8026Sopenharmony_ci
506