From d79e4ae455d527ac53eb67f2dcb8e4bf8eef33b0 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 26 Jul 2024 14:29:44 -0500 Subject: [PATCH] Added LFS_O_CKMETA/CKDATA flags These flags just call lfsr_file_ckmeta/ckdata under the hood, but make it very easy to check metadata/data when opening a file. As an extra plus they implicitly close the file on failure, so might make cleanup easier. Of course, everything has a cost: code stack before: 36368 2664 after: 36424 (+0.2%) 2664 (+0.0%) These also ruin my previous "you don't pay for what you don't call" assertion, since runtime flags unfortunately always pull in code. We should add a compile-time switch for these evntually. --- lfs.c | 21 ++++++++++++++++++++- lfs.h | 2 ++ tests/test_ck.toml | 21 +++++++++++++++++++-- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/lfs.c b/lfs.c index 731bb58e..e2561fad 100644 --- a/lfs.c +++ b/lfs.c @@ -5926,6 +5926,14 @@ static inline bool lfsr_o_isdesync(uint32_t flags) { return flags & LFS_O_DESYNC; } +static inline bool lfsr_o_isckmeta(uint32_t flags) { + return flags & LFS_O_CKMETA; +} + +static inline bool lfsr_o_isckdata(uint32_t flags) { + return flags & LFS_O_CKDATA; +} + // internal open flags static inline uint8_t lfsr_f_type(uint32_t flags) { return flags >> 24; @@ -9888,6 +9896,8 @@ static inline lfs_off_t lfsr_file_size_(const lfsr_file_t *file) { // needed in lfsr_file_opencfg static lfs_ssize_t lfsr_file_read_(lfs_t *lfs, const lfsr_file_t *file, lfs_off_t pos, uint8_t *buffer, lfs_size_t size); +static int lfsr_file_ck(lfs_t *lfs, const lfsr_file_t *file, + uint32_t flags); int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file, const char *path, uint32_t flags, @@ -10067,6 +10077,14 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file, file->o.bshrub = LFSR_BSHRUB_BNULL(); } + // check metadata/data for errors? + if (lfsr_o_isckmeta(flags) || lfsr_o_isckdata(flags)) { + err = lfsr_file_ck(lfs, file, flags); + if (err) { + goto failed; + } + } + // add to tracked mdirs lfsr_omdir_open(lfs, &file->o.o); return 0; @@ -11745,7 +11763,8 @@ failed:; } // file check functions -static int lfsr_file_ck(lfs_t *lfs, lfsr_file_t *file, uint32_t flags) { +static int lfsr_file_ck(lfs_t *lfs, const lfsr_file_t *file, + uint32_t flags) { // traverse the file's btree lfsr_btraversal_t bt = LFSR_BTRAVERSAL(); while (true) { diff --git a/lfs.h b/lfs.h index d3c44bc7..ee4e5cd7 100644 --- a/lfs.h +++ b/lfs.h @@ -136,6 +136,8 @@ enum lfs_type { #define LFS_O_FLUSH 0x00000040 // Flush data on every write #define LFS_O_SYNC 0x00000080 // Sync metadata on every write #define LFS_O_DESYNC 0x00000100 // Do not sync or recieve file updates +#define LFS_O_CKMETA 0x00001000 // Check metadata checksums +#define LFS_O_CKDATA 0x00002000 // Check metadata + data checksums // internally used flags #define LFS_F_TYPE 0xff000000 // The file's type diff --git a/tests/test_ck.toml b/tests/test_ck.toml index 50b69737..0beaa5d6 100644 --- a/tests/test_ck.toml +++ b/tests/test_ck.toml @@ -269,6 +269,7 @@ done:; [cases.test_ck_file_ckmeta_easy] # METHOD=0 => lfsr_file_ckmeta # METHOD=1 => lfsr_file_close+open+ckmeta +# METHOD=2 => lfsr_file_close+open defines.METHOD = [0, 1] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.SIZE = [ @@ -345,11 +346,18 @@ code = ''' lfsr_file_open(&lfs, &file, "octopus", LFS_O_RDONLY) => 0; lfsr_file_ckmeta(&lfs, &file) => LFS_ERR_CORRUPT; + // find clobbered blocks with lfsr_file_close+open + } else if (METHOD == 2) { + lfsr_file_open(&lfs, &file, "octopus", + LFS_O_RDONLY | LFS_O_CKMETA) => LFS_ERR_CORRUPT; + } else { assert(false); } - lfsr_file_close(&lfs, &file) => 0; + if (METHOD != 2) { + lfsr_file_close(&lfs, &file) => 0; + } lfsr_unmount(&lfs) => 0; } done:; @@ -359,6 +367,7 @@ done:; [cases.test_ck_file_ckdata_easy] # METHOD=0 => lfsr_file_ckdata # METHOD=1 => lfsr_file_close+open+ckdata +# METHOD=2 => lfsr_file_close+open defines.METHOD = [0, 1] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.SIZE = [ @@ -436,11 +445,19 @@ code = ''' lfsr_file_open(&lfs, &file, "octopus", LFS_O_RDONLY) => 0; lfsr_file_ckdata(&lfs, &file) => LFS_ERR_CORRUPT; + // find clobbered blocks with lfsr_file_close+open + } else if (METHOD == 2) { + lfsr_file_close(&lfs, &file) => 0; + lfsr_file_open(&lfs, &file, "octopus", + LFS_O_RDONLY | LFS_O_CKDATA) => LFS_ERR_CORRUPT; + } else { assert(false); } - lfsr_file_close(&lfs, &file) => 0; + if (METHOD != 2) { + lfsr_file_close(&lfs, &file) => 0; + } lfsr_unmount(&lfs) => 0; } done:;