From ad2e8b34981de4ca98bcf23141b39dcb6ec54043 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sat, 15 Nov 2025 02:10:42 -0600 Subject: [PATCH] Changed mkgbmap/rmgbmap to error if NOENT/EXIST This more closely matches behavior of functions like mkdir and remove, even though mkgbmap/rmgbmap operate on a special object and not files. Besides, returning an error is more useful as users are always free to ignore said error. Adds what appears to be one literal to mkgbmap (curiously not rmgbmap? snuck into alignment?): code stack ctx before: 35968 2280 660 after: 35968 (+0.0%) 2280 (+0.0%) 660 (+0.0%) code stack ctx gbmap before: 38824 2296 772 gbmap after: 38828 (+0.0%) 2296 (+0.0%) 772 (+0.0%) --- lfs3.c | 8 +- tests/test_gbmap.toml | 294 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 298 insertions(+), 4 deletions(-) diff --git a/lfs3.c b/lfs3.c index ed33942a..a3e3b9f4 100644 --- a/lfs3.c +++ b/lfs3.c @@ -16540,9 +16540,9 @@ failed:; // enable the global on-disk block-map #if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP) && !defined(LFS3_YES_GBMAP) int lfs3_fs_mkgbmap(lfs3_t *lfs3) { - // do nothing if we already have a gbmap + // error if we already have a gbmap if (lfs3_f_isgbmap(lfs3->flags)) { - return 0; + return LFS3_ERR_EXIST; } // prepare our filesystem for writing @@ -16599,9 +16599,9 @@ failed:; // disable the global on-disk block-map #if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP) && !defined(LFS3_YES_GBMAP) int lfs3_fs_rmgbmap(lfs3_t *lfs3) { - // do nothing if we already don't have a gbmap + // error if we already don't have a gbmap if (!lfs3_f_isgbmap(lfs3->flags)) { - return 0; + return LFS3_ERR_NOENT; } // prepare our filesystem for writing diff --git a/tests/test_gbmap.toml b/tests/test_gbmap.toml index f869937c..a13c64b7 100644 --- a/tests/test_gbmap.toml +++ b/tests/test_gbmap.toml @@ -1167,3 +1167,297 @@ code = ''' lfs3_unmount(&lfs3) => 0; ''' + +# test that removing a non-existant gbmap errors +[cases.test_gbmap_rmgbmap_noent] +ifndef = 'LFS3_YES_GBMAP' +defines.COUNT = [ + 'BLOCK_COUNT', + 'BLOCK_COUNT-1', + 'BLOCK_COUNT/2', + 'BLOCK_COUNT/4', + '5', + '3', +] +defines.SIZE = [ + 'BLOCK_SIZE', + '2*BLOCK_SIZE', + '8*BLOCK_SIZE', +] +defines.N = ['5', 'BLOCK_COUNT/2'] +defines.WRAPAROUND = 3 +# REMOUNT=0 => don't remount +# REMOUNT=1 => remount after +# REMOUNT=2 => remount before +# REMOUNT=3 => remount both after and before +defines.REMOUNT = [0, 1, 2, 3] +if = [ + 'COUNT >= 3', + 'COUNT >= 2*N*SIZE/BLOCK_SIZE', +] +code = ''' + // test various block counts + struct lfs3_cfg cfg = *CFG; + cfg.block_count = COUNT; + lfs3_t lfs3; + // note the lack of gbmap flag + lfs3_format(&lfs3, LFS3_F_RDWR, &cfg) => 0; + lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0; + + // check that we were formatted without the gbmap + struct lfs3_fsinfo fsinfo; + lfs3_fs_stat(&lfs3, &fsinfo) => 0; + assert(!(fsinfo.flags & LFS3_I_GBMAP)); + + // create n files repeatedly until we're sure we've wrapped around + // a few times + uint32_t prng = 42; + uint32_t prng_ = prng; + for (lfs3_size_t i = 0; + i < (WRAPAROUND*COUNT) + / (N*(SIZE/BLOCK_SIZE)); + i++) { + prng = prng_; + for (lfs3_size_t n = 0; n < N; n++) { + char name[256]; + sprintf(name, "file%08d", n); + + uint8_t wbuf[SIZE]; + for (lfs3_size_t j = 0; j < SIZE; j++) { + wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26); + } + + lfs3_file_t file; + lfs3_file_open(&lfs3, &file, name, + LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0; + lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE; + lfs3_file_close(&lfs3, &file) => 0; + } + } + + // remount before? + if (REMOUNT & 2) { + lfs3_unmount(&lfs3) => 0; + lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0; + } + + // now try to remove the gbmap + lfs3_fs_rmgbmap(&lfs3) => LFS3_ERR_NOENT; + + // remount after? + if (REMOUNT & 1) { + lfs3_unmount(&lfs3) => 0; + lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0; + } + + // we should no longer have a gbmap + lfs3_fs_stat(&lfs3, &fsinfo) => 0; + assert(!(fsinfo.flags & LFS3_I_GBMAP)); + + // create n files repeatedly until we're sure we've wrapped around + // a few times + for (lfs3_size_t i = 0; + i < (WRAPAROUND*COUNT) + / (N*(SIZE/BLOCK_SIZE)); + i++) { + prng = prng_; + for (lfs3_size_t n = 0; n < N; n++) { + char name[256]; + sprintf(name, "file%08d", n); + + uint8_t wbuf[SIZE]; + for (lfs3_size_t j = 0; j < SIZE; j++) { + wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26); + } + + lfs3_file_t file; + lfs3_file_open(&lfs3, &file, name, + LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0; + lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE; + lfs3_file_close(&lfs3, &file) => 0; + } + } + + for (int remount = 0; remount < 2; remount++) { + // remount? + if (remount) { + lfs3_unmount(&lfs3) => 0; + lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0; + } + + // check that our file writes worked + prng_ = prng; + for (lfs3_size_t i = 0; i < N; i++) { + // check with stat + char name[256]; + sprintf(name, "file%08d", i); + struct lfs3_info info; + lfs3_stat(&lfs3, name, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS3_TYPE_REG); + assert(info.size == SIZE); + + // try reading the file, note we reset prng above + uint8_t wbuf[SIZE]; + for (lfs3_size_t j = 0; j < SIZE; j++) { + wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26); + } + + lfs3_file_t file; + uint8_t rbuf[SIZE]; + lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0; + lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE; + assert(memcmp(rbuf, wbuf, SIZE) == 0); + lfs3_file_close(&lfs3, &file) => 0; + } + } + + lfs3_unmount(&lfs3) => 0; +''' + +# test that making an existant gbmap errors +[cases.test_gbmap_mkgbmap_exist] +ifndef = 'LFS3_YES_GBMAP' +defines.COUNT = [ + 'BLOCK_COUNT', + 'BLOCK_COUNT-1', + 'BLOCK_COUNT/2', + 'BLOCK_COUNT/4', + '5', + '3', +] +defines.SIZE = [ + 'BLOCK_SIZE', + '2*BLOCK_SIZE', + '8*BLOCK_SIZE', +] +defines.N = ['5', 'BLOCK_COUNT/2'] +defines.WRAPAROUND = 3 +# REMOUNT=0 => don't remount +# REMOUNT=1 => remount after +# REMOUNT=2 => remount before +# REMOUNT=3 => remount both after and before +defines.REMOUNT = [0, 1, 2, 3] +if = [ + 'COUNT >= 3', + 'COUNT >= 2*N*SIZE/BLOCK_SIZE', +] +code = ''' + // test various block counts + struct lfs3_cfg cfg = *CFG; + cfg.block_count = COUNT; + lfs3_t lfs3; + // note the gbmap flag + lfs3_format(&lfs3, LFS3_F_RDWR | LFS3_F_GBMAP, &cfg) => 0; + lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0; + + // check that we were formatted with the gbmap + struct lfs3_fsinfo fsinfo; + lfs3_fs_stat(&lfs3, &fsinfo) => 0; + assert(fsinfo.flags & LFS3_I_GBMAP); + + // create n files repeatedly until we're sure we've wrapped around + // a few times + uint32_t prng = 42; + uint32_t prng_ = prng; + for (lfs3_size_t i = 0; + i < (WRAPAROUND*COUNT) + / (N*(SIZE/BLOCK_SIZE)); + i++) { + prng = prng_; + for (lfs3_size_t n = 0; n < N; n++) { + char name[256]; + sprintf(name, "file%08d", n); + + uint8_t wbuf[SIZE]; + for (lfs3_size_t j = 0; j < SIZE; j++) { + wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26); + } + + lfs3_file_t file; + lfs3_file_open(&lfs3, &file, name, + LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0; + lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE; + lfs3_file_close(&lfs3, &file) => 0; + } + } + + // remount before? + if (REMOUNT & 2) { + lfs3_unmount(&lfs3) => 0; + lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0; + } + + // now make the gbmap + lfs3_fs_mkgbmap(&lfs3) => LFS3_ERR_EXIST; + + // remount after? + if (REMOUNT & 1) { + lfs3_unmount(&lfs3) => 0; + lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0; + } + + // we should now have a gbmap + lfs3_fs_stat(&lfs3, &fsinfo) => 0; + assert(fsinfo.flags & LFS3_I_GBMAP); + + // create n files repeatedly until we're sure we've wrapped around + // a few times + for (lfs3_size_t i = 0; + i < (WRAPAROUND*COUNT) + / (N*(SIZE/BLOCK_SIZE)); + i++) { + prng = prng_; + for (lfs3_size_t n = 0; n < N; n++) { + char name[256]; + sprintf(name, "file%08d", n); + + uint8_t wbuf[SIZE]; + for (lfs3_size_t j = 0; j < SIZE; j++) { + wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26); + } + + lfs3_file_t file; + lfs3_file_open(&lfs3, &file, name, + LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0; + lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE; + lfs3_file_close(&lfs3, &file) => 0; + } + } + + for (int remount = 0; remount < 2; remount++) { + // remount? + if (remount) { + lfs3_unmount(&lfs3) => 0; + lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0; + } + + // check that our file writes worked + prng_ = prng; + for (lfs3_size_t i = 0; i < N; i++) { + // check with stat + char name[256]; + sprintf(name, "file%08d", i); + struct lfs3_info info; + lfs3_stat(&lfs3, name, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS3_TYPE_REG); + assert(info.size == SIZE); + + // try reading the file, note we reset prng above + uint8_t wbuf[SIZE]; + for (lfs3_size_t j = 0; j < SIZE; j++) { + wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26); + } + + lfs3_file_t file; + uint8_t rbuf[SIZE]; + lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0; + lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE; + assert(memcmp(rbuf, wbuf, SIZE) == 0); + lfs3_file_close(&lfs3, &file) => 0; + } + } + + lfs3_unmount(&lfs3) => 0; +'''