diff --git a/lfs.c b/lfs.c index 33175b6e..f3c83e55 100644 --- a/lfs.c +++ b/lfs.c @@ -699,18 +699,18 @@ static int lfsr_bd_set(lfs_t *lfs, lfs_block_t block, lfs_size_t off, /// lfsr_ck_t stuff /// -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY #define LFSR_CK_ISPARITY 0x80000000 #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY #define LFSR_CK_CKSUM(_cksize, _cksum) \ ((lfsr_ck_t){ \ .cksize=_cksize, \ .u.cksum=_cksum}) #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY #define LFSR_CK_PARITY(_ckoff, _cksize) \ ((lfsr_ck_t){ \ .cksize=LFSR_CK_ISPARITY | (_cksize), \ @@ -718,25 +718,25 @@ static int lfsr_bd_set(lfs_t *lfs, lfs_block_t block, lfs_size_t off, #endif // ck helpers -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY static inline bool lfsr_ck_isparity(lfsr_ck_t ck) { return ck.cksize & LFSR_CK_ISPARITY; } #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY static inline bool lfsr_ck_iscksum(lfsr_ck_t ck) { return !(ck.cksize & LFSR_CK_ISPARITY); } #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY static inline lfs_size_t lfsr_ck_cksize(lfsr_ck_t ck) { return ck.cksize & ~LFSR_CK_ISPARITY; } #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY static inline lfs_size_t lfsr_ck_ckoff(lfsr_ck_t ck) { if (lfsr_ck_isparity(ck)) { return ck.u.ckoff; @@ -751,23 +751,23 @@ static inline lfs_size_t lfsr_ck_ckoff(lfsr_ck_t ck) { // tailck tracks the most recent trunk's parity so we can parity-check // if it hasn't been written to disk yet -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY #define LFSR_TAILCK_PARITY 0x80000000 #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY static inline bool lfsr_tailck_parity(const lfsr_tailck_t *tailck) { return tailck->ckoff & LFSR_TAILCK_PARITY; } #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY static inline lfs_size_t lfsr_tailck_ckoff(const lfsr_tailck_t *tailck) { return tailck->ckoff & ~LFSR_TAILCK_PARITY; } #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY // read the pesky parity byte from disk static lfs_sbool_t lfsr_bd_readparity(lfs_t *lfs, lfs_block_t block, lfs_size_t off, lfs_size_t hint) { @@ -801,7 +801,7 @@ static lfs_sbool_t lfsr_bd_readparity(lfs_t *lfs, } #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY static lfs_ssize_t lfsr_bd_ckprefix(lfs_t *lfs, lfs_block_t block, lfs_size_t off, lfs_size_t hint, lfsr_ck_t ck, @@ -809,6 +809,8 @@ static lfs_ssize_t lfsr_bd_ckprefix(lfs_t *lfs, // must be in-bounds LFS_ASSERT(block < lfs->block_count); LFS_ASSERT(lfsr_ck_ckoff(ck)+lfsr_ck_cksize(ck) <= lfs->cfg->block_size); + // only parity checking is supported + LFS_ASSERT(lfsr_ck_isparity(ck)); // make sure hint includes our prefix/suffix/pesky parity byte lfs_size_t hint_ = lfs_max( @@ -816,7 +818,7 @@ static lfs_ssize_t lfsr_bd_ckprefix(lfs_t *lfs, (off-lfsr_ck_ckoff(ck)) + lfs_min( hint, lfs->cfg->block_size - off), - lfsr_ck_cksize(ck) + ((lfsr_ck_isparity(ck)) ? 1 : 0)); + lfsr_ck_cksize(ck) + 1); // checksum any prefixed data int err = lfsr_bd_cksum(lfs, @@ -833,7 +835,7 @@ static lfs_ssize_t lfsr_bd_ckprefix(lfs_t *lfs, } #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY static int lfsr_bd_cksuffix(lfs_t *lfs, lfs_block_t block, lfs_size_t off, lfs_size_t hint, lfsr_ck_t ck, @@ -841,6 +843,8 @@ static int lfsr_bd_cksuffix(lfs_t *lfs, // must be in-bounds LFS_ASSERT(block < lfs->block_count); LFS_ASSERT(lfsr_ck_ckoff(ck)+lfsr_ck_cksize(ck) <= lfs->cfg->block_size); + // only parity checking is supported + LFS_ASSERT(lfsr_ck_isparity(ck)); // make sure hint includes our pesky parity byte lfs_size_t hint_ = lfs_max( @@ -856,46 +860,34 @@ static int lfsr_bd_cksuffix(lfs_t *lfs, return err; } - if (lfsr_ck_isparity(ck)) { - // need to read the next byte, which should contain our parity - LFS_ASSERT(lfsr_ck_ckoff(ck)+lfsr_ck_cksize(ck) - < lfs->cfg->block_size); - lfs_sbool_t parity = lfsr_bd_readparity(lfs, - block, lfsr_ck_ckoff(ck)+lfsr_ck_cksize(ck), - hint_ - (lfsr_ck_cksize(ck)-off)); - if (parity < 0) { - return parity; - } - - // does parity match? - if (lfs_parity(cksum) != parity) { - LFS_ERROR("Found ckread parity mismatch " - "0x%"PRIx32".%"PRIx32" %"PRId32", " - "parity %01"PRIx32" (!= %01"PRIx32")", - block, lfsr_ck_ckoff(ck), lfsr_ck_cksize(ck), - lfs_parity(cksum), parity); - return LFS_ERR_CORRUPT; - } - } else { - // do checksums match? - if (cksum != ck.u.cksum) { - LFS_ERROR("Found ckread cksum mismatch " - "0x%"PRIx32".%"PRIx32" %"PRId32", " - "cksum %08"PRIx32" (!= %08"PRIx32")", - block, lfsr_ck_ckoff(ck), lfsr_ck_cksize(ck), - cksum, ck.u.cksum); - return LFS_ERR_CORRUPT; - } + // need to read the next byte, which should contain our parity + LFS_ASSERT(lfsr_ck_ckoff(ck)+lfsr_ck_cksize(ck) + < lfs->cfg->block_size); + lfs_sbool_t parity = lfsr_bd_readparity(lfs, + block, lfsr_ck_ckoff(ck)+lfsr_ck_cksize(ck), + hint_ - (lfsr_ck_cksize(ck)-off)); + if (parity < 0) { + return parity; + } + + // does parity match? + if (lfs_parity(cksum) != parity) { + LFS_ERROR("Found ckparity mismatch " + "0x%"PRIx32".%"PRIx32" %"PRId32", " + "parity %01"PRIx32" (!= %01"PRIx32")", + block, lfsr_ck_ckoff(ck), lfsr_ck_cksize(ck), + lfs_parity(cksum), parity); + return LFS_ERR_CORRUPT; } return 0; } #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY // caching read with parity/checksum checks // -// the main downside of ckreads is we need to read all data that +// the main downside of checking reads is we need to read all data that // contributes to the relevant parity/checksum, this may be // significantly more than the data we actually end up using // @@ -939,16 +931,17 @@ static int lfsr_bd_readck_(lfs_t *lfs, } #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY // needed in lfsr_bd_readck -static inline bool lfsr_m_isckreads(uint32_t flags); +static inline bool lfsr_m_isckparity(uint32_t flags); static int lfsr_bd_readck(lfs_t *lfs, lfs_block_t block, lfs_size_t off, lfs_size_t hint, void *buffer, lfs_size_t size, lfsr_ck_t ck) { - // are we actually checking reads? - if (lfsr_m_isckreads(lfs->flags)) { + // check this read? + if (lfsr_m_isckparity(lfs->flags) + && lfsr_ck_isparity(ck)) { return lfsr_bd_readck_(lfs, block, off, hint, buffer, size, @@ -962,7 +955,7 @@ static int lfsr_bd_readck(lfs_t *lfs, #endif // redirect to lfsr_bd_read if not checking reads -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY #define LFSR_BD_READCK(_lfs, _block, _off, _hint, _buffer, _size, _ck) \ lfsr_bd_readck(_lfs, _block, _off, _hint, _buffer, _size, _ck) #else @@ -976,7 +969,7 @@ static int lfsr_bd_readck(lfs_t *lfs, // // we'd also need to worry about early termination in lfsr_bd_cmp/cmpck -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY static lfs_scmp_t lfsr_bd_cmpck_(lfs_t *lfs, lfs_block_t block, lfs_size_t off, lfs_size_t hint, const void *buffer, lfs_size_t size, @@ -1037,13 +1030,14 @@ static lfs_scmp_t lfsr_bd_cmpck_(lfs_t *lfs, } #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY static lfs_scmp_t lfsr_bd_cmpck(lfs_t *lfs, lfs_block_t block, lfs_size_t off, lfs_size_t hint, const void *buffer, lfs_size_t size, lfsr_ck_t ck) { - // are we actually checking reads? - if (lfsr_m_isckreads(lfs->flags)) { + // check this read? + if (lfsr_m_isckparity(lfs->flags) + && lfsr_ck_isparity(ck)) { return lfsr_bd_cmpck_(lfs, block, off, hint, buffer, size, @@ -1057,7 +1051,7 @@ static lfs_scmp_t lfsr_bd_cmpck(lfs_t *lfs, #endif // redirect to lfsr_bd_cmp if not checking reads -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY #define LFSR_BD_CMPCK(_lfs, _block, _off, _hint, _buffer, _size, _ck) \ lfsr_bd_cmpck(_lfs, _block, _off, _hint, _buffer, _size, _ck) #else @@ -1065,7 +1059,7 @@ static lfs_scmp_t lfsr_bd_cmpck(lfs_t *lfs, lfsr_bd_cmp(_lfs, _block, _off, _hint, _buffer, _size) #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY static int lfsr_bd_cpyck_(lfs_t *lfs, lfs_block_t dst_block, lfs_size_t dst_off, lfs_block_t src_block, lfs_size_t src_off, lfs_size_t hint, @@ -1137,15 +1131,16 @@ static int lfsr_bd_cpyck_(lfs_t *lfs, } #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY static int lfsr_bd_cpyck(lfs_t *lfs, lfs_block_t dst_block, lfs_size_t dst_off, lfs_block_t src_block, lfs_size_t src_off, lfs_size_t hint, lfs_size_t size, lfsr_ck_t ck, uint32_t *cksum, bool align) { - // are we actually checking reads? - if (lfsr_m_isckreads(lfs->flags)) { + // check this read? + if (lfsr_m_isckparity(lfs->flags) + && lfsr_ck_isparity(ck)) { return lfsr_bd_cpyck_(lfs, dst_block, dst_off, src_block, src_off, hint, @@ -1163,7 +1158,7 @@ static int lfsr_bd_cpyck(lfs_t *lfs, #endif // redirect to lfsr_bd_cpy if not checking reads -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY #define LFSR_BD_CPYCK(_lfs, \ _dst_block, _dst_off, \ _src_block, _src_off, _hint, \ @@ -1711,13 +1706,13 @@ static lfs_ssize_t lfsr_bd_readtag(lfs_t *lfs, *cksum = lfs_crc32c(*cksum, tag_buf, d); } - #ifdef LFS_CKREADS + #ifdef LFS_CKPARITY // check the parity if we're checking reads and not already // calculating a checksum // // this requires reading all of the data as well, but with any luck // the data will stick around in the cache - if (lfsr_m_isckreads(lfs->flags) && !cksum) { + if (lfsr_m_isckparity(lfs->flags) && !cksum) { // pesky parity byte lfs_size_t size__ = (!lfsr_tag_isalt(tag)) ? size : 0; if (off+d+size__ >= lfs->cfg->block_size) { @@ -1808,7 +1803,7 @@ static lfs_ssize_t lfsr_bd_progtag(lfs_t *lfs, .size=_size, \ .u.buffer=(const void*)(_buffer)}) -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY #define LFSR_DATA_DISKCKSUM(_block, _off, _size, _cksize, _cksum) \ ((lfsr_data_t){ \ .size=LFSR_DATA_ONDISK | (_size), \ @@ -1823,7 +1818,7 @@ static lfs_ssize_t lfsr_bd_progtag(lfs_t *lfs, .u.disk.off=_off}) #endif -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY #define LFSR_DATA_DISKPARITY(_block, _off, _size, _ckoff, _cksize) \ ((lfsr_data_t){ \ .size=LFSR_DATA_ONDISK | (_size), \ @@ -2481,11 +2476,11 @@ static int lfsr_data_readecksum(lfs_t *lfs, lfsr_data_t *data, #define LFSR_DATA_BPTR(_bptr) \ LFSR_DATA_BPTR_(_bptr, (uint8_t[LFSR_BPTR_DSIZE]){0}) -// checked reads introduces ck info into lfsr_data_t that we don't want -// to unnecessarily duplicate, so accessing ck info gets annoyingly -// messy... +// checked reads adds ck info to lfsr_data_t that we don't want to +// unnecessarily duplicate, long story short accessing ck info gets +// annoyingly messy... static inline lfs_size_t lfsr_bptr_cksize(const lfsr_bptr_t *bptr) { - #ifdef LFS_CKREADS + #ifdef LFS_CKPARITY return bptr->data.u.disk.ck.cksize; #else return bptr->cksize; @@ -2493,7 +2488,7 @@ static inline lfs_size_t lfsr_bptr_cksize(const lfsr_bptr_t *bptr) { } static inline uint32_t lfsr_bptr_cksum(const lfsr_bptr_t *bptr) { - #ifdef LFS_CKREADS + #ifdef LFS_CKPARITY return bptr->data.u.disk.ck.u.cksum; #else return bptr->cksum; @@ -2564,7 +2559,7 @@ static int lfsr_data_readbptr(lfs_t *lfs, lfsr_data_t *data, // read the cksize, cksum err = lfsr_data_readlleb128(lfs, data, - LFS_IFDEF_CKREADS( + LFS_IFDEF_CKPARITY( &bptr->data.u.disk.ck.cksize, &bptr->cksize)); if (err) { @@ -2572,7 +2567,7 @@ static int lfsr_data_readbptr(lfs_t *lfs, lfsr_data_t *data, } err = lfsr_data_readle32(lfs, data, - LFS_IFDEF_CKREADS( + LFS_IFDEF_CKPARITY( &bptr->data.u.disk.ck.u.cksum, &bptr->cksum)); if (err) { @@ -3245,7 +3240,7 @@ static int lfsr_rbyd_appendtag(lfs_t *lfs, lfsr_rbyd_t *rbyd, rbyd->eoff += d; - #ifdef LFS_CKREADS + #ifdef LFS_CKPARITY // keep track of most recent parity lfs->tailck.ckblock = rbyd->blocks[0]; lfs->tailck.ckoff @@ -3276,7 +3271,7 @@ static int lfsr_rbyd_appendcat(lfs_t *lfs, lfsr_rbyd_t *rbyd, rbyd->eoff += lfsr_cat_size(cat, count); - #ifdef LFS_CKREADS + #ifdef LFS_CKPARITY // keep track of most recent parity lfs->tailck.ckblock = rbyd->blocks[0]; lfs->tailck.ckoff @@ -6766,9 +6761,9 @@ static inline bool lfsr_m_isckprogs(uint32_t flags) { } #endif -#ifdef LFS_CKREADS -static inline bool lfsr_m_isckreads(uint32_t flags) { - return flags & LFS_M_CKREADS; +#ifdef LFS_CKPARITY +static inline bool lfsr_m_isckparity(uint32_t flags) { + return flags & LFS_M_CKPARITY; } #endif @@ -11291,7 +11286,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file, LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_BLOCK, -(bid+1 - pos), LFSR_DATA_BPTR_( - LFS_IFDEF_CKREADS( + LFS_IFDEF_CKPARITY( (&(lfsr_bptr_t){ .data=left_slice_}), (&(lfsr_bptr_t){ @@ -11349,7 +11344,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file, tag_, bid+1 - (pos+weight), LFSR_DATA_BPTR_( - LFS_IFDEF_CKREADS( + LFS_IFDEF_CKPARITY( (&(lfsr_bptr_t){ .data=right_slice_}), (&(lfsr_bptr_t){ @@ -11595,10 +11590,10 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file, } bptr.data = LFSR_DATA_DISKCKSUM(block, 0, 0, 0, 0); - LFS_IFDEF_CKREADS( + LFS_IFDEF_CKPARITY( bptr.data.u.disk.ck.cksize, bptr.cksize) = 0; - LFS_IFDEF_CKREADS( + LFS_IFDEF_CKPARITY( bptr.data.u.disk.ck.u.cksum, bptr.cksum) = 0; @@ -11631,7 +11626,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file, int err = lfsr_bd_prog(lfs, bptr.data.u.disk.block, lfsr_bptr_cksize(&bptr), &buffer[pos_ - pos], d_, - LFS_IFDEF_CKREADS( + LFS_IFDEF_CKPARITY( &bptr.data.u.disk.ck.u.cksum, &bptr.cksum), true); if (err) { @@ -11644,7 +11639,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file, } pos_ += d_; - LFS_IFDEF_CKREADS( + LFS_IFDEF_CKPARITY( bptr.data.u.disk.ck.cksize, bptr.cksize) += d_; d -= d_; @@ -11707,7 +11702,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file, lfsr_data_slice(bptr_.data, pos_ - (bid_-(weight_-1)), d_), - LFS_IFDEF_CKREADS( + LFS_IFDEF_CKPARITY( &bptr.data.u.disk.ck.u.cksum, &bptr.cksum), true); if (err) { @@ -11720,7 +11715,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file, } pos_ += d_; - LFS_IFDEF_CKREADS( + LFS_IFDEF_CKPARITY( bptr.data.u.disk.ck.cksize, bptr.cksize) += d_; d -= d_; @@ -11734,7 +11729,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file, int err = lfsr_bd_set(lfs, bptr.data.u.disk.block, lfsr_bptr_cksize(&bptr), 0, d, - LFS_IFDEF_CKREADS( + LFS_IFDEF_CKPARITY( &bptr.data.u.disk.ck.u.cksum, &bptr.cksum), true); if (err) { @@ -11747,7 +11742,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file, } pos_ += d; - LFS_IFDEF_CKREADS( + LFS_IFDEF_CKPARITY( bptr.data.u.disk.ck.cksize, bptr.cksize) += d; } @@ -11758,12 +11753,12 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file, // up reading more than is strictly necessary. lfs_ssize_t d = lfsr_bptr_cksize(&bptr) % lfs->cfg->prog_size; lfs->pcache.size -= d; - LFS_IFDEF_CKREADS( + LFS_IFDEF_CKPARITY( bptr.data.u.disk.ck.cksize, bptr.cksize) -= d; // finalize our write - int err = lfsr_bd_flush(lfs, LFS_IFDEF_CKREADS( + int err = lfsr_bd_flush(lfs, LFS_IFDEF_CKPARITY( &bptr.data.u.disk.ck.u.cksum, &bptr.cksum), true); if (err) { @@ -12791,7 +12786,7 @@ static int lfs_init(lfs_t *lfs, uint32_t flags, } } - #ifdef LFS_CKREADS + #ifdef LFS_CKPARITY // setup tailck, nothing should actually check off=0 lfs->tailck.ckblock = 0; lfs->tailck.ckoff = 0; @@ -13501,11 +13496,11 @@ int lfsr_mount(lfs_t *lfs, uint32_t flags, LFS_ASSERT((flags & ~( LFS_M_RDWR | LFS_M_RDONLY - | LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, 0) - | LFS_IFDEF_CKREADS(LFS_M_CKREADS, 0) - | LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, 0) | LFS_M_FLUSH | LFS_M_SYNC + | LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, 0) + | LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, 0) + | LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, 0) | LFS_M_MTREEONLY | LFS_M_MKCONSISTENT | LFS_M_LOOKAHEAD @@ -13659,8 +13654,8 @@ int lfsr_format(lfs_t *lfs, uint32_t flags, LFS_ASSERT((flags & ~( LFS_F_RDWR | LFS_IFDEF_CKPROGS(LFS_F_CKPROGS, 0) - | LFS_IFDEF_CKREADS(LFS_F_CKREADS, 0) | LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, 0) + | LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, 0) | LFS_F_MTREEONLY | LFS_F_COMPACT | LFS_F_CKMETA @@ -13724,11 +13719,11 @@ int lfsr_fs_stat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) { // return various filesystem flags fsinfo->flags = lfs->flags & ( LFS_I_RDONLY - | LFS_IFDEF_CKPROGS(LFS_I_CKPROGS, 0) - | LFS_IFDEF_CKREADS(LFS_I_CKREADS, 0) - | LFS_IFDEF_CKFETCHES(LFS_I_CKFETCHES, 0) | LFS_I_FLUSH | LFS_I_SYNC + | LFS_IFDEF_CKPROGS(LFS_I_CKPROGS, 0) + | LFS_IFDEF_CKFETCHES(LFS_I_CKFETCHES, 0) + | LFS_IFDEF_CKPARITY(LFS_I_CKPARITY, 0) | LFS_I_UNCOMPACTED); // some flags we calculate on demand fsinfo->flags |= (lfsr_fs_isinconsistent(lfs)) ? LFS_I_INCONSISTENT : 0; diff --git a/lfs.h b/lfs.h index 6697fe4d..8c8582fd 100644 --- a/lfs.h +++ b/lfs.h @@ -156,11 +156,11 @@ enum lfs_type { #ifdef LFS_CKPROGS #define LFS_F_CKPROGS 0x00100000 // Check progs by reading back progged data #endif -#ifdef LFS_CKREADS -#define LFS_F_CKREADS 0x00200000 // Check reads via parity bits/checksums -#endif #ifdef LFS_CKFETCHES -#define LFS_F_CKFETCHES 0x00400000 // Check checksums before reads +#define LFS_F_CKFETCHES 0x00200000 // Check block checksums before first use +#endif +#ifdef LFS_CKPARITY +#define LFS_F_CKPARITY 0x00400000 // Check tag parity bits on reads #endif #define LFS_F_MTREEONLY 0x00000800 // Only traverse the mtree @@ -176,11 +176,11 @@ enum lfs_type { #ifdef LFS_CKPROGS #define LFS_M_CKPROGS 0x00100000 // Check progs by reading back progged data #endif -#ifdef LFS_CKREADS -#define LFS_M_CKREADS 0x00200000 // Check reads via parity bits/checksums -#endif #ifdef LFS_CKFETCHES -#define LFS_M_CKFETCHES 0x00400000 // Check checksums before reads +#define LFS_M_CKFETCHES 0x00200000 // Check block checksums before first use +#endif +#ifdef LFS_CKPARITY +#define LFS_M_CKPARITY 0x00400000 // Check tag parity bits on reads #endif #define LFS_M_MTREEONLY 0x00000800 // Only traverse the mtree @@ -198,11 +198,11 @@ enum lfs_type { #ifdef LFS_CKPROGS #define LFS_I_CKPROGS 0x00100000 // Filesystem mounted with LFS_M_CKPROGS #endif -#ifdef LFS_CKREADS -#define LFS_I_CKREADS 0x00200000 // Filesystem mounted with LFS_M_CKREADS -#endif #ifdef LFS_CKFETCHES -#define LFS_I_CKFETCHES 0x00400000 // Filesystem mounted with LFS_M_CKFETCHES +#define LFS_I_CKFETCHES 0x00200000 // Filesystem mounted with LFS_M_CKFETCHES +#endif +#ifdef LFS_CKPARITY +#define LFS_I_CKPARITY 0x00400000 // Filesystem mounted with LFS_M_CKPARITY #endif #define LFS_I_INCONSISTENT \ @@ -559,7 +559,7 @@ typedef struct lfsr_omdir { // lfs_block_t tail[2]; //} lfs_mdir_t; -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY // context for validating data typedef struct lfsr_ck { // sign(cksize)=0 => cksum check @@ -582,7 +582,7 @@ typedef struct lfsr_data { struct { lfs_block_t block; lfs_size_t off; - #ifdef LFS_CKREADS + #ifdef LFS_CKPARITY lfsr_ck_t ck; #endif } disk; @@ -615,7 +615,7 @@ typedef lfsr_data_t lfsr_sprout_t; typedef struct lfsr_bptr { lfsr_data_t data; - #ifndef LFS_CKREADS + #ifndef LFS_CKPARITY lfs_size_t cksize; uint32_t cksum; #endif @@ -757,7 +757,7 @@ typedef struct lfsr_grm { lfsr_smid_t mids[2]; } lfsr_grm_t; -#ifdef LFS_CKREADS +#ifdef LFS_CKPARITY typedef struct lfsr_tailck { lfs_block_t ckblock; // sign(ckoff) => tail parity @@ -797,7 +797,7 @@ typedef struct lfs { uint8_t *buffer; } pcache; - #ifdef LFS_CKREADS + #ifdef LFS_CKPARITY lfsr_tailck_t tailck; #endif diff --git a/lfs_util.h b/lfs_util.h index dc56e1cd..c0af33d9 100644 --- a/lfs_util.h +++ b/lfs_util.h @@ -144,18 +144,18 @@ extern "C" #define LFS_IFDEF_CKPROGS(a, b) (b) #endif -#ifdef LFS_CKREADS -#define LFS_IFDEF_CKREADS(a, b) (a) -#else -#define LFS_IFDEF_CKREADS(a, b) (b) -#endif - #ifdef LFS_CKFETCHES #define LFS_IFDEF_CKFETCHES(a, b) (a) #else #define LFS_IFDEF_CKFETCHES(a, b) (b) #endif +#ifdef LFS_CKPARITY +#define LFS_IFDEF_CKPARITY(a, b) (a) +#else +#define LFS_IFDEF_CKPARITY(a, b) (b) +#endif + // Builtin functions, these may be replaced by more efficient // toolchain-specific implementations. LFS_NO_BUILTINS falls back to a more diff --git a/tests/test_ck.toml b/tests/test_ck.toml index 700e81dc..5730b9ca 100644 --- a/tests/test_ck.toml +++ b/tests/test_ck.toml @@ -767,132 +767,72 @@ code = ''' -# Some simple ckread tests - -# These tests were originally intended to test all single-bit -# metastability errors with ckreads, however they quickly found that -# ckreads can't actually guarantee single-bit error-detection since -# the bit flip may alter the leb128 encoded size field and find a new, -# erronous, parity bit. -# -# For example, one bit flip: -# -# 40 0c 00 12 80 0d ff ff -# '----.----' ^--------------------. -# '- altble 0xc w0 -18 parity=1 -# -# 40 0c 80 12 80 0d ff ff -# '-------.-------' ^----------------------. -# '- altble 0xc w2304 -1664 parity=1 -# -# This doesn't make ckreads _completely_ useless, just mostly useless. -# We can still use it to check parity bits, but without a systematic -# proof. -# -# So for now these tests are sort of in stasis, limited to testing -# metastability in areas we know we can detect (revision counts, raw -# data blocks, etc). Maybe future features will make them more useful. -# +# Some simple ckfetches tests # test every single-bit error in block 0/1 -[cases.test_ck_ckreads_mroot] +[cases.test_ck_ckfetches_mroot] defines.BADBLOCK = [0, 1] defines.BADBIT = -1 -defines.BADBLOCK_BEHAVIOR = [ - 'LFS_EMUBD_BADBLOCK_PROGFLIP', - 'LFS_EMUBD_BADBLOCK_READFLIP', -] # this should stay inlined defines.SIZE = 'BLOCK_SIZE/16' -ifdef = 'LFS_CKREADS' +ifdef = 'LFS_CKFETCHES' code = ''' // test all bad bits in the mroot for (lfs_size_t i = 0; - // we can't detect metastable tags, so limit read-flips - // to our revision count - i < ((BADBIT == -1) ? 8*4 : 1); + i < ((BADBIT == -1) ? 8*BLOCK_SIZE : 1); i++) { lfs_size_t badbit = (BADBIT == -1) ? i : BADBIT; - - // reset the bd prng every run for reproducibility - lfs_emubd_seed(CFG, 42); printf("--- badblock: 0x%x.%x, badbit: 0x%x (0x%x+%x) ---\n", (lfs_size_t)BADBLOCK, badbit/8, badbit, badbit/8, badbit%8); - // mark our badbit as bad - lfs_emubd_markbadbit(CFG, BADBLOCK, badbit) => 0; - - // With metastability, basically any filesystem operation can - // return LFS_ERR_CORRUPT. This is ok, what we're really testing - // for is no internal/external asserts failing. - // format lfs_t lfs; - int err = lfsr_format(&lfs, LFS_M_RDWR | LFS_M_CKREADS, CFG); - assert(!err || err == LFS_ERR_CORRUPT); - if (err == LFS_ERR_CORRUPT) { - goto corrupt; - } - err = lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKREADS, CFG); - assert(!err || err == LFS_ERR_CORRUPT); - if (err == LFS_ERR_CORRUPT) { - goto corrupt; - } + lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKFETCHES, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; { // create a file lfsr_file_t file; - err = lfsr_file_open(&lfs, &file, "tripedalia", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL); - assert(!err || err == LFS_ERR_CORRUPT); - if (err == LFS_ERR_CORRUPT) { - goto corrupt_mounted; - } + lfsr_file_open(&lfs, &file, "stygiomedusa", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; uint32_t prng = 42; uint8_t wbuf[SIZE]; for (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); } - lfs_ssize_t res = lfsr_file_write(&lfs, &file, wbuf, SIZE); - assert(res == SIZE || res == LFS_ERR_CORRUPT); - if (res == LFS_ERR_CORRUPT) { - lfsr_file_close(&lfs, &file) => 0; - goto corrupt_mounted; - } - err = lfsr_file_close(&lfs, &file); - if (err == LFS_ERR_CORRUPT) { - goto corrupt_mounted; - } + lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; + lfsr_file_close(&lfs, &file) => 0; // try to read our file for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; - err = lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKREADS, CFG); + + // flip our badbit + lfs_emubd_flipbit(CFG, BADBLOCK, badbit) => 0; + + int err = lfsr_mount(&lfs, + LFS_M_RDWR | LFS_M_CKFETCHES, CFG); + assert(!err || err == LFS_ERR_CORRUPT); if (err == LFS_ERR_CORRUPT) { goto corrupt; } } // yes reads can fail here - err = lfsr_file_open(&lfs, &file, "tripedalia", LFS_O_RDONLY); + int err = lfsr_file_open(&lfs, &file, + "stygiomedusa", LFS_O_RDONLY); assert(!err - || err == LFS_ERR_CORRUPT // bit errors can also cause our fs state to "rollback", - // which is not great but we can't solve this with ckreads - // alone + // which is not great but we can't solve this with + // ckfetches alone || err == LFS_ERR_NOENT); - if (err == LFS_ERR_CORRUPT || err == LFS_ERR_NOENT) { + if (err == LFS_ERR_NOENT) { goto corrupt_mounted; } uint8_t rbuf[SIZE]; - lfs_ssize_t res = lfsr_file_read(&lfs, &file, rbuf, SIZE); - assert(res == SIZE || res == LFS_ERR_CORRUPT); - if (res == LFS_ERR_CORRUPT) { - lfsr_file_close(&lfs, &file) => 0; - goto corrupt_mounted; - } + lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; assert(memcmp(rbuf, wbuf, SIZE) == 0); lfsr_file_close(&lfs, &file) => 0; } @@ -908,15 +848,11 @@ code = ''' ''' # test every single-bit error in a file's data block -[cases.test_ck_ckreads_data] +[cases.test_ck_ckfetches_data] defines.BADBIT = -1 -defines.BADBLOCK_BEHAVIOR = [ - 'LFS_EMUBD_BADBLOCK_PROGFLIP', - 'LFS_EMUBD_BADBLOCK_READFLIP', -] # this should create a single block file defines.SIZE = 'BLOCK_SIZE' -ifdef = 'LFS_CKREADS' +ifdef = 'LFS_CKFETCHES' code = ''' // first we need to figure out where the data block will actually // end up, fortunately our block randomization is intentionally @@ -924,12 +860,12 @@ code = ''' // format lfs_t lfs; - lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKREADS, CFG) => 0; - lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKREADS, CFG) => 0; + lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKFETCHES, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; // create a file lfsr_file_t file; - lfsr_file_open(&lfs, &file, "tripedalia", + lfsr_file_open(&lfs, &file, "stygiomedusa", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; uint32_t prng = 42; uint8_t wbuf[SIZE]; @@ -960,62 +896,43 @@ code = ''' i < ((BADBIT == -1) ? 8*BLOCK_SIZE : 1); i++) { lfs_size_t badbit = (BADBIT == -1) ? i : BADBIT; - - // reset the bd prng every run for reproducibility - lfs_emubd_seed(CFG, 42); printf("--- badblock: 0x%x.%x, badbit: 0x%x (0x%x+%x) ---\n", badblock, badbit/8, badbit, badbit/8, badbit%8); - // mark our badbit as bad - lfs_emubd_markbadbit(CFG, badblock, badbit) => 0; - - // With metastability, basically any filesystem operation can - // return LFS_ERR_CORRUPT. This is ok, what we're really testing - // for is no internal/external asserts failing. - // format lfs_t lfs; - lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKREADS, CFG) => 0; - lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKREADS, CFG) => 0; + lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKFETCHES, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; { // create a file lfsr_file_t file; - lfsr_file_open(&lfs, &file, "tripedalia", + lfsr_file_open(&lfs, &file, "stygiomedusa", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; uint32_t prng = 42; uint8_t wbuf[SIZE]; for (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); } - lfs_ssize_t res = lfsr_file_write(&lfs, &file, wbuf, SIZE); - assert(res == SIZE || res == LFS_ERR_CORRUPT); - if (res == LFS_ERR_CORRUPT) { - lfsr_file_close(&lfs, &file) => 0; - goto corrupt_mounted; - } - int err = lfsr_file_close(&lfs, &file); - if (err == LFS_ERR_CORRUPT) { - goto corrupt_mounted; - } + lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; + lfsr_file_close(&lfs, &file) => 0; + + // flip our badbit + lfs_emubd_flipbit(CFG, badblock, badbit) => 0; // try to read our file for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; - lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKREADS, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; } // yes reads can fail here - err = lfsr_file_open(&lfs, &file, "tripedalia", LFS_O_RDONLY); - assert(!err - || err == LFS_ERR_CORRUPT - // bit errors can also cause our fs state to "rollback", - // which is not great but we can't solve this with ckreads - // alone - || err == LFS_ERR_NOENT); - if (err == LFS_ERR_CORRUPT || err == LFS_ERR_NOENT) { + int err = lfsr_file_open(&lfs, &file, + "stygiomedusa", LFS_O_RDONLY); + assert(!err || err == LFS_ERR_CORRUPT); + if (err == LFS_ERR_CORRUPT) { goto corrupt_mounted; } uint8_t rbuf[SIZE]; @@ -1039,18 +956,14 @@ code = ''' ''' # test every single-bit error in a file's btree node -[cases.test_ck_ckreads_btree] +[cases.test_ck_ckfetches_btree] defines.BADBIT = -1 -defines.BADBLOCK_BEHAVIOR = [ - 'LFS_EMUBD_BADBLOCK_PROGFLIP', - 'LFS_EMUBD_BADBLOCK_READFLIP', -] # force the file to create a btree defines.INLINE_SIZE = 0 defines.CRYSTAL_THRESH = -1 defines.FRAGMENT_SIZE = 'BLOCK_SIZE/8' defines.SIZE = '2*FRAGMENT_SIZE' -ifdef = 'LFS_CKREADS' +ifdef = 'LFS_CKFETCHES' code = ''' // first we need to figure out where the btree block will actually // end up, fortunately our block randomization is intentionally @@ -1058,12 +971,12 @@ code = ''' // format lfs_t lfs; - lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKREADS, CFG) => 0; - lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKREADS, CFG) => 0; + lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKFETCHES, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; // create a file lfsr_file_t file; - lfsr_file_open(&lfs, &file, "bathykorus", + lfsr_file_open(&lfs, &file, "stygiomedusa", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; uint32_t prng = 42; uint8_t wbuf[SIZE]; @@ -1091,67 +1004,46 @@ code = ''' // now test all bad bits in the btree block for (lfs_size_t i = 0; - // we can't detect metastable tags, so limit read-flips - // to our revision count - i < ((BADBIT == -1) ? 8*4 : 1); + i < ((BADBIT == -1) ? 8*BLOCK_SIZE : 1); i++) { lfs_size_t badbit = (BADBIT == -1) ? i : BADBIT; - - // reset the bd prng every run for reproducibility - lfs_emubd_seed(CFG, 42); printf("--- badblock: 0x%x.%x, badbit: 0x%x (0x%x+%x) ---\n", badblock, badbit/8, badbit, badbit/8, badbit%8); - // mark our badbit as bad - lfs_emubd_markbadbit(CFG, badblock, badbit) => 0; - - // With metastability, basically any filesystem operation can - // return LFS_ERR_CORRUPT. This is ok, what we're really testing - // for is no internal/external asserts failing. - // format lfs_t lfs; - lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKREADS, CFG) => 0; - lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKREADS, CFG) => 0; + lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKFETCHES, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; { // create a file lfsr_file_t file; - lfsr_file_open(&lfs, &file, "bathykorus", + lfsr_file_open(&lfs, &file, "stygiomedusa", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; uint32_t prng = 42; uint8_t wbuf[SIZE]; for (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); } - lfs_ssize_t res = lfsr_file_write(&lfs, &file, wbuf, SIZE); - assert(res == SIZE || res == LFS_ERR_CORRUPT); - if (res == LFS_ERR_CORRUPT) { - lfsr_file_close(&lfs, &file) => 0; - goto corrupt_mounted; - } - int err = lfsr_file_close(&lfs, &file); - if (err == LFS_ERR_CORRUPT) { - goto corrupt_mounted; - } + lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; + lfsr_file_close(&lfs, &file) => 0; + + // flip our badbit + lfs_emubd_flipbit(CFG, badblock, badbit) => 0; // try to read our file for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; - lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKREADS, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; } // yes reads can fail here - err = lfsr_file_open(&lfs, &file, "bathykorus", LFS_O_RDONLY); - assert(!err - || err == LFS_ERR_CORRUPT - // bit errors can also cause our fs state to "rollback", - // which is not great but we can't solve this with ckreads - // alone - || err == LFS_ERR_NOENT); - if (err == LFS_ERR_CORRUPT || err == LFS_ERR_NOENT) { + int err = lfsr_file_open(&lfs, &file, + "stygiomedusa", LFS_O_RDONLY); + assert(!err || err == LFS_ERR_CORRUPT); + if (err == LFS_ERR_CORRUPT) { goto corrupt_mounted; } uint8_t rbuf[SIZE]; @@ -1176,172 +1068,123 @@ code = ''' -# Some simple ckfetches tests +# Some simple ckparity tests + +# These tests were originally intended to test all single-bit +# metastability errors with ckparity, however they quickly found that +# ckparity can't actually guarantee single-bit error-detection since +# the bit flip may alter the leb128 encoded size field and find a new, +# erronous, parity bit. +# +# For example, one bit flip: +# +# 40 0c 00 12 80 0d ff ff +# '----.----' ^--------------------. +# '- altble 0xc w0 -18 parity=1 +# +# 40 0c 80 12 80 0d ff ff +# '-------.-------' ^----------------------. +# '- altble 0xc w2304 -1664 parity=1 +# +# This doesn't make ckparity _completely_ useless, just mostly useless. +# We can still use it to check parity bits, but without a systematic +# proof. +# +# So for now these tests are sort of in stasis, limited to testing +# metastability in areas we know we can detect (revision counts, raw +# data blocks, etc). Maybe future features will make them more useful. +# # test every single-bit error in block 0/1 -[cases.test_ck_ckfetches_mroot] +[cases.test_ck_ckparity_mroot] defines.BADBLOCK = [0, 1] defines.BADBIT = -1 +defines.BADBLOCK_BEHAVIOR = [ + 'LFS_EMUBD_BADBLOCK_PROGFLIP', + 'LFS_EMUBD_BADBLOCK_READFLIP', +] # this should stay inlined defines.SIZE = 'BLOCK_SIZE/16' -ifdef = 'LFS_CKFETCHES' +ifdef = 'LFS_CKPARITY' code = ''' // test all bad bits in the mroot for (lfs_size_t i = 0; - i < ((BADBIT == -1) ? 8*BLOCK_SIZE : 1); + // we can't detect metastable tags, so limit read-flips + // to our revision count + i < ((BADBIT == -1) ? 8*4 : 1); i++) { lfs_size_t badbit = (BADBIT == -1) ? i : BADBIT; + + // reset the bd prng every run for reproducibility + lfs_emubd_seed(CFG, 42); printf("--- badblock: 0x%x.%x, badbit: 0x%x (0x%x+%x) ---\n", (lfs_size_t)BADBLOCK, badbit/8, badbit, badbit/8, badbit%8); + // mark our badbit as bad + lfs_emubd_markbadbit(CFG, BADBLOCK, badbit) => 0; + + // With metastability, basically any filesystem operation can + // return LFS_ERR_CORRUPT. This is ok, what we're really testing + // for is no internal/external asserts failing. + // format lfs_t lfs; - lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKFETCHES, CFG) => 0; - lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; + int err = lfsr_format(&lfs, LFS_M_RDWR | LFS_M_CKPARITY, CFG); + assert(!err || err == LFS_ERR_CORRUPT); + if (err == LFS_ERR_CORRUPT) { + goto corrupt; + } + err = lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKPARITY, CFG); + assert(!err || err == LFS_ERR_CORRUPT); + if (err == LFS_ERR_CORRUPT) { + goto corrupt; + } { // create a file lfsr_file_t file; - lfsr_file_open(&lfs, &file, "stygiomedusa", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + err = lfsr_file_open(&lfs, &file, "tripedalia", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL); + assert(!err || err == LFS_ERR_CORRUPT); + if (err == LFS_ERR_CORRUPT) { + goto corrupt_mounted; + } uint32_t prng = 42; uint8_t wbuf[SIZE]; for (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); } - lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; - lfsr_file_close(&lfs, &file) => 0; + lfs_ssize_t res = lfsr_file_write(&lfs, &file, wbuf, SIZE); + assert(res == SIZE || res == LFS_ERR_CORRUPT); + if (res == LFS_ERR_CORRUPT) { + lfsr_file_close(&lfs, &file) => 0; + goto corrupt_mounted; + } + err = lfsr_file_close(&lfs, &file); + if (err == LFS_ERR_CORRUPT) { + goto corrupt_mounted; + } // try to read our file for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; - - // flip our badbit - lfs_emubd_flipbit(CFG, BADBLOCK, badbit) => 0; - - int err = lfsr_mount(&lfs, - LFS_M_RDWR | LFS_M_CKFETCHES, CFG); - assert(!err || err == LFS_ERR_CORRUPT); + err = lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKPARITY, CFG); if (err == LFS_ERR_CORRUPT) { goto corrupt; } } // yes reads can fail here - int err = lfsr_file_open(&lfs, &file, - "stygiomedusa", LFS_O_RDONLY); + err = lfsr_file_open(&lfs, &file, "tripedalia", LFS_O_RDONLY); assert(!err + || err == LFS_ERR_CORRUPT // bit errors can also cause our fs state to "rollback", // which is not great but we can't solve this with - // ckfetches alone + // ckparity alone || err == LFS_ERR_NOENT); - if (err == LFS_ERR_NOENT) { - goto corrupt_mounted; - } - uint8_t rbuf[SIZE]; - lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; - assert(memcmp(rbuf, wbuf, SIZE) == 0); - lfsr_file_close(&lfs, &file) => 0; - } - } - - corrupt_mounted:; - lfsr_unmount(&lfs) => 0; - - corrupt:; - // reset badbit - lfs_emubd_markgood(CFG, BADBLOCK) => 0; - } -''' - -# test every single-bit error in a file's data block -[cases.test_ck_ckfetches_data] -defines.BADBIT = -1 -# this should create a single block file -defines.SIZE = 'BLOCK_SIZE' -ifdef = 'LFS_CKFETCHES' -code = ''' - // first we need to figure out where the data block will actually - // end up, fortunately our block randomization is intentionally - // consistent - - // format - lfs_t lfs; - lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKFETCHES, CFG) => 0; - lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; - - // create a file - lfsr_file_t file; - lfsr_file_open(&lfs, &file, "stygiomedusa", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - uint32_t prng = 42; - uint8_t wbuf[SIZE]; - for (lfs_size_t j = 0; j < SIZE; j++) { - wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); - } - lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; - lfsr_file_close(&lfs, &file) => 0; - - // find the data block - lfsr_traversal_t t; - lfsr_traversal_open(&lfs, &t, 0) => 0; - lfs_block_t badblock; - while (true) { - struct lfs_tinfo tinfo; - lfsr_traversal_read(&lfs, &t, &tinfo) => 0; - if (tinfo.btype == LFS_BTYPE_DATA) { - badblock = tinfo.block; - break; - } - } - lfsr_traversal_close(&lfs, &t) => 0; - - lfsr_unmount(&lfs) => 0; - - // now test all bad bits in the data block - for (lfs_size_t i = 0; - i < ((BADBIT == -1) ? 8*BLOCK_SIZE : 1); - i++) { - lfs_size_t badbit = (BADBIT == -1) ? i : BADBIT; - printf("--- badblock: 0x%x.%x, badbit: 0x%x (0x%x+%x) ---\n", - badblock, badbit/8, badbit, badbit/8, badbit%8); - - // format - lfs_t lfs; - lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKFETCHES, CFG) => 0; - lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; - - { - // create a file - lfsr_file_t file; - lfsr_file_open(&lfs, &file, "stygiomedusa", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - uint32_t prng = 42; - uint8_t wbuf[SIZE]; - for (lfs_size_t j = 0; j < SIZE; j++) { - wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); - } - lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; - lfsr_file_close(&lfs, &file) => 0; - - // flip our badbit - lfs_emubd_flipbit(CFG, badblock, badbit) => 0; - - // try to read our file - for (int remount = 0; remount < 2; remount++) { - // remount? - if (remount) { - lfsr_unmount(&lfs) => 0; - lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; - } - - // yes reads can fail here - int err = lfsr_file_open(&lfs, &file, - "stygiomedusa", LFS_O_RDONLY); - assert(!err || err == LFS_ERR_CORRUPT); - if (err == LFS_ERR_CORRUPT) { + if (err == LFS_ERR_CORRUPT || err == LFS_ERR_NOENT) { goto corrupt_mounted; } uint8_t rbuf[SIZE]; @@ -1359,20 +1202,25 @@ code = ''' corrupt_mounted:; lfsr_unmount(&lfs) => 0; + corrupt:; // reset badbit - lfs_emubd_markgood(CFG, badblock) => 0; + lfs_emubd_markgood(CFG, BADBLOCK) => 0; } ''' # test every single-bit error in a file's btree node -[cases.test_ck_ckfetches_btree] +[cases.test_ck_ckparity_btree] defines.BADBIT = -1 +defines.BADBLOCK_BEHAVIOR = [ + 'LFS_EMUBD_BADBLOCK_PROGFLIP', + 'LFS_EMUBD_BADBLOCK_READFLIP', +] # force the file to create a btree defines.INLINE_SIZE = 0 defines.CRYSTAL_THRESH = -1 defines.FRAGMENT_SIZE = 'BLOCK_SIZE/8' defines.SIZE = '2*FRAGMENT_SIZE' -ifdef = 'LFS_CKFETCHES' +ifdef = 'LFS_CKPARITY' code = ''' // first we need to figure out where the btree block will actually // end up, fortunately our block randomization is intentionally @@ -1380,12 +1228,12 @@ code = ''' // format lfs_t lfs; - lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKFETCHES, CFG) => 0; - lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; + lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKPARITY, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKPARITY, CFG) => 0; // create a file lfsr_file_t file; - lfsr_file_open(&lfs, &file, "stygiomedusa", + lfsr_file_open(&lfs, &file, "bathykorus", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; uint32_t prng = 42; uint8_t wbuf[SIZE]; @@ -1413,46 +1261,67 @@ code = ''' // now test all bad bits in the btree block for (lfs_size_t i = 0; - i < ((BADBIT == -1) ? 8*BLOCK_SIZE : 1); + // we can't detect metastable tags, so limit read-flips + // to our revision count + i < ((BADBIT == -1) ? 8*4 : 1); i++) { lfs_size_t badbit = (BADBIT == -1) ? i : BADBIT; + + // reset the bd prng every run for reproducibility + lfs_emubd_seed(CFG, 42); printf("--- badblock: 0x%x.%x, badbit: 0x%x (0x%x+%x) ---\n", badblock, badbit/8, badbit, badbit/8, badbit%8); + // mark our badbit as bad + lfs_emubd_markbadbit(CFG, badblock, badbit) => 0; + + // With metastability, basically any filesystem operation can + // return LFS_ERR_CORRUPT. This is ok, what we're really testing + // for is no internal/external asserts failing. + // format lfs_t lfs; - lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKFETCHES, CFG) => 0; - lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; + lfsr_format(&lfs, LFS_F_RDWR | LFS_F_CKPARITY, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKPARITY, CFG) => 0; { // create a file lfsr_file_t file; - lfsr_file_open(&lfs, &file, "stygiomedusa", + lfsr_file_open(&lfs, &file, "bathykorus", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; uint32_t prng = 42; uint8_t wbuf[SIZE]; for (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); } - lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE; - lfsr_file_close(&lfs, &file) => 0; - - // flip our badbit - lfs_emubd_flipbit(CFG, badblock, badbit) => 0; + lfs_ssize_t res = lfsr_file_write(&lfs, &file, wbuf, SIZE); + assert(res == SIZE || res == LFS_ERR_CORRUPT); + if (res == LFS_ERR_CORRUPT) { + lfsr_file_close(&lfs, &file) => 0; + goto corrupt_mounted; + } + int err = lfsr_file_close(&lfs, &file); + if (err == LFS_ERR_CORRUPT) { + goto corrupt_mounted; + } // try to read our file for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; - lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKFETCHES, CFG) => 0; + lfsr_mount(&lfs, LFS_M_RDWR | LFS_M_CKPARITY, CFG) => 0; } // yes reads can fail here - int err = lfsr_file_open(&lfs, &file, - "stygiomedusa", LFS_O_RDONLY); - assert(!err || err == LFS_ERR_CORRUPT); - if (err == LFS_ERR_CORRUPT) { + err = lfsr_file_open(&lfs, &file, "bathykorus", LFS_O_RDONLY); + assert(!err + || err == LFS_ERR_CORRUPT + // bit errors can also cause our fs state to "rollback", + // which is not great but we can't solve this with + // ckparity alone + || err == LFS_ERR_NOENT); + if (err == LFS_ERR_CORRUPT || err == LFS_ERR_NOENT) { goto corrupt_mounted; } uint8_t rbuf[SIZE]; @@ -1477,6 +1346,7 @@ code = ''' + ## High-level error spam tests # # we basically just throw errors at filesystem operations until they @@ -1488,22 +1358,22 @@ code = ''' [cases.test_ck_spam_dir_fuzz] # TODO enable other methods once rollback protection is in place # METHOD=0 => ckprogs -# METHOD=1 => ckreads -# METHOD=2 => ckfetches +# METHOD=1 => ckfetches +# METHOD=2 => ckparity defines.METHOD = [0] defines.PERIOD = 10 defines.PROTECTED_MROOTANCHOR = [false, true] defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_PROGFLIP' defines.CKPROGS = 'METHOD == 0' -defines.CKREADS = 'METHOD == 1' -defines.CKFETCHES = 'METHOD == 2' +defines.CKFETCHES = 'METHOD == 1' +defines.CKPARITY = 'METHOD == 2' defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256] defines.SEED = 'range(10)' fuzz = 'SEED' if = [ 'LFS_IFDEF_CKPROGS(true, !CKPROGS)', - 'LFS_IFDEF_CKREADS(true, !CKREADS)', 'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)', + 'LFS_IFDEF_CKPARITY(true, !CKPARITY)', ] code = ''' // seed our block device with our seed so we have different error @@ -1523,14 +1393,14 @@ code = ''' lfsr_format(&lfs, LFS_F_RDWR | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_F_CKPROGS, -1) : 0) - | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_F_CKREADS, -1) : 0) - | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0), + | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0) + | ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0), CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0) - | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_M_CKREADS, -1) : 0) - | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0), + | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0) + | ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0), CFG) => 0; // set up a simulation to compare against @@ -1551,13 +1421,13 @@ code = ''' // types of errors, so we implement errors for each one a // bit differently - // ckprogs? ckreads? - if (METHOD == 0 || METHOD == 1) { + // ckprogs? ckparity? + if (METHOD == 0 || METHOD == 2) { // mark our badblock as bad lfs_emubd_markbad(CFG, badblock) => 0; // ckfetches? - } else if (METHOD == 2) { + } else if (METHOD == 1) { // flip a bit lfs_emubd_flipbit(CFG, badblock, lfs_emubd_prng(CFG) % (BLOCK_SIZE*8)) => 0; @@ -1668,11 +1538,11 @@ code = ''' | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0) - | ((CKREADS) - ? LFS_IFDEF_CKREADS(LFS_M_CKREADS, -1) - : 0) | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) + : 0) + | ((CKPARITY) + ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0), CFG) => 0; } @@ -1729,15 +1599,15 @@ corrupt_mounted:; [cases.test_ck_spam_file_fuzz] # TODO enable other methods once rollback protection is in place # METHOD=0 => ckprogs -# METHOD=1 => ckreads -# METHOD=2 => ckfetches +# METHOD=1 => ckfetches +# METHOD=2 => ckparity defines.METHOD = [0] defines.PERIOD = 10 defines.PROTECTED_MROOTANCHOR = [false, true] defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_PROGFLIP' defines.CKPROGS = 'METHOD == 0' -defines.CKREADS = 'METHOD == 1' -defines.CKFETCHES = 'METHOD == 2' +defines.CKFETCHES = 'METHOD == 1' +defines.CKPARITY = 'METHOD == 2' defines.N = [1, 2, 4, 8, 16, 32, 64] defines.SIZE = [ '0', @@ -1752,8 +1622,8 @@ defines.SEED = 'range(10)' fuzz = 'SEED' if = [ 'LFS_IFDEF_CKPROGS(true, !CKPROGS)', - 'LFS_IFDEF_CKREADS(true, !CKREADS)', 'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)', + 'LFS_IFDEF_CKPARITY(true, !CKPARITY)', '(SIZE*N)/BLOCK_SIZE <= 16', ] code = ''' @@ -1774,14 +1644,14 @@ code = ''' lfsr_format(&lfs, LFS_F_RDWR | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_F_CKPROGS, -1) : 0) - | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_F_CKREADS, -1) : 0) - | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0), + | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0) + | ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0), CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0) - | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_M_CKREADS, -1) : 0) - | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0), + | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0) + | ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0), CFG) => 0; // set up a simulation to compare against @@ -1803,13 +1673,13 @@ code = ''' // types of errors, so we implement errors for each one a // bit differently - // ckprogs? ckreads? - if (METHOD == 0 || METHOD == 1) { + // ckprogs? ckparity? + if (METHOD == 0 || METHOD == 2) { // mark our badblock as bad lfs_emubd_markbad(CFG, badblock) => 0; // ckfetches? - } else if (METHOD == 2) { + } else if (METHOD == 1) { // flip a bit lfs_emubd_flipbit(CFG, badblock, lfs_emubd_prng(CFG) % (BLOCK_SIZE*8)) => 0; @@ -1966,11 +1836,11 @@ code = ''' | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0) - | ((CKREADS) - ? LFS_IFDEF_CKREADS(LFS_M_CKREADS, -1) - : 0) | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) + : 0) + | ((CKPARITY) + ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0), CFG) => 0; } @@ -2042,15 +1912,15 @@ corrupt_mounted:; [cases.test_ck_spam_fwrite_fuzz] # TODO enable other methods once rollback protection is in place # METHOD=0 => ckprogs -# METHOD=1 => ckreads -# METHOD=2 => ckfetches +# METHOD=1 => ckfetches +# METHOD=2 => ckparity defines.METHOD = [0] defines.PERIOD = 10 defines.PROTECTED_MROOTANCHOR = [false, true] defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_PROGFLIP' defines.CKPROGS = 'METHOD == 0' -defines.CKREADS = 'METHOD == 1' -defines.CKFETCHES = 'METHOD == 2' +defines.CKFETCHES = 'METHOD == 1' +defines.CKPARITY = 'METHOD == 2' defines.SIZE = [ 'FILE_BUFFER_SIZE/2', '2*FILE_BUFFER_SIZE', @@ -2070,8 +1940,8 @@ defines.SEED = 'range(10)' fuzz = 'SEED' if = [ 'LFS_IFDEF_CKPROGS(true, !CKPROGS)', - 'LFS_IFDEF_CKREADS(true, !CKREADS)', 'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)', + 'LFS_IFDEF_CKPARITY(true, !CKPARITY)', 'CHUNK <= SIZE', # this just saves testing time 'SIZE <= 4*1024*FRAGMENT_SIZE', @@ -2094,14 +1964,14 @@ code = ''' lfsr_format(&lfs, LFS_F_RDWR | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_F_CKPROGS, -1) : 0) - | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_F_CKREADS, -1) : 0) - | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0), + | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0) + | ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0), CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0) - | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_M_CKREADS, -1) : 0) - | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0), + | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0) + | ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0), CFG) => 0; // create a file @@ -2145,13 +2015,13 @@ code = ''' // types of errors, so we implement errors for each one a // bit differently - // ckprogs? ckreads? - if (METHOD == 0 || METHOD == 1) { + // ckprogs? ckparity? + if (METHOD == 0 || METHOD == 2) { // mark our badblock as bad lfs_emubd_markbad(CFG, badblock) => 0; // ckfetches? - } else if (METHOD == 2) { + } else if (METHOD == 1) { // flip a bit lfs_emubd_flipbit(CFG, badblock, lfs_emubd_prng(CFG) % (BLOCK_SIZE*8)) => 0; @@ -2208,11 +2078,11 @@ code = ''' | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0) - | ((CKREADS) - ? LFS_IFDEF_CKREADS(LFS_M_CKREADS, -1) - : 0) | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) + : 0) + | ((CKPARITY) + ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0), CFG) => 0; } @@ -2270,15 +2140,15 @@ corrupt_mounted:; defines.BADBLOCK = -1 # TODO enable other methods once rollback protection is in place # METHOD=0 => ckprogs -# METHOD=1 => ckreads -# METHOD=2 => ckfetches +# METHOD=1 => ckfetches +# METHOD=2 => ckparity defines.METHOD = [0] defines.PERIOD = 10 defines.PROTECTED_MROOTANCHOR = [false, true] defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_PROGFLIP' defines.CKPROGS = 'METHOD == 0' -defines.CKREADS = 'METHOD == 1' -defines.CKFETCHES = 'METHOD == 2' +defines.CKFETCHES = 'METHOD == 1' +defines.CKPARITY = 'METHOD == 2' defines.N = [1, 2, 4, 8, 16, 32, 64] defines.SIZE = [ '0', @@ -2293,8 +2163,8 @@ defines.SEED = 'range(10)' fuzz = 'SEED' if = [ 'LFS_IFDEF_CKPROGS(true, !CKPROGS)', - 'LFS_IFDEF_CKREADS(true, !CKREADS)', 'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)', + 'LFS_IFDEF_CKPARITY(true, !CKPARITY)', '(SIZE*N)/BLOCK_SIZE <= 16', ] code = ''' @@ -2315,14 +2185,14 @@ code = ''' lfsr_format(&lfs, LFS_F_RDWR | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_F_CKPROGS, -1) : 0) - | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_F_CKREADS, -1) : 0) - | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0), + | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0) + | ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0), CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0) - | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_M_CKREADS, -1) : 0) - | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0), + | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0) + | ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0), CFG) => 0; // set up a simulation to compare against @@ -2354,13 +2224,13 @@ code = ''' // types of errors, so we implement errors for each one a // bit differently - // ckprogs? ckreads? - if (METHOD == 0 || METHOD == 1) { + // ckprogs? ckparity? + if (METHOD == 0 || METHOD == 2) { // mark our badblock as bad lfs_emubd_markbad(CFG, badblock) => 0; // ckfetches? - } else if (METHOD == 2) { + } else if (METHOD == 1) { // flip a bit lfs_emubd_flipbit(CFG, badblock, lfs_emubd_prng(CFG) % (BLOCK_SIZE*8)) => 0; @@ -2704,15 +2574,15 @@ corrupt_mounted:; [cases.test_ck_spam_ozd_fuzz] # TODO enable other methods once rollback protection is in place # METHOD=0 => ckprogs -# METHOD=1 => ckreads -# METHOD=2 => ckfetches +# METHOD=1 => ckfetches +# METHOD=2 => ckparity defines.METHOD = [0] defines.PERIOD = 10 defines.PROTECTED_MROOTANCHOR = [false, true] defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_PROGFLIP' defines.CKPROGS = 'METHOD == 0' -defines.CKREADS = 'METHOD == 1' -defines.CKFETCHES = 'METHOD == 2' +defines.CKFETCHES = 'METHOD == 1' +defines.CKPARITY = 'METHOD == 2' defines.N = [1, 2, 4, 8, 16, 32, 64] defines.SIZE = [ '0', @@ -2727,9 +2597,8 @@ defines.SEED = 'range(10)' fuzz = 'SEED' if = [ 'LFS_IFDEF_CKPROGS(true, !CKPROGS)', - 'LFS_IFDEF_CKREADS(true, !CKREADS)', 'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)', - 'LFS_IFDEF_CKPROGS(true, !CKPROGS)', + 'LFS_IFDEF_CKPARITY(true, !CKPARITY)', '(SIZE*N)/BLOCK_SIZE <= 16', ] code = ''' @@ -2750,14 +2619,14 @@ code = ''' lfsr_format(&lfs, LFS_F_RDWR | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_F_CKPROGS, -1) : 0) - | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_F_CKREADS, -1) : 0) - | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0), + | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0) + | ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0), CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0) - | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_M_CKREADS, -1) : 0) - | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0), + | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0) + | ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0), CFG) => 0; // set up a simulation to compare against @@ -2790,13 +2659,13 @@ code = ''' // types of errors, so we implement errors for each one a // bit differently - // ckprogs? ckreads? - if (METHOD == 0 || METHOD == 1) { + // ckprogs? ckparity? + if (METHOD == 0 || METHOD == 2) { // mark our badblock as bad lfs_emubd_markbad(CFG, badblock) => 0; // ckfetches? - } else if (METHOD == 2) { + } else if (METHOD == 1) { // flip a bit lfs_emubd_flipbit(CFG, badblock, lfs_emubd_prng(CFG) % (BLOCK_SIZE*8)) => 0; diff --git a/tests/test_mount.toml b/tests/test_mount.toml index ad13bab7..706b2e5d 100644 --- a/tests/test_mount.toml +++ b/tests/test_mount.toml @@ -15,11 +15,11 @@ code = ''' # lfsr_fs_stat [cases.test_mount_flags] defines.RDONLY = [false, true] -defines.CKPROGS = [false, true] -defines.CKREADS = [false, true] -defines.CKFETCHES = [false, true] defines.FLUSH = [false, true] defines.SYNC = [false, true] +defines.CKPROGS = [false, true] +defines.CKFETCHES = [false, true] +defines.CKPARITY = [false, true] defines.MTREEONLY = [false, true] defines.MKCONSISTENT = [false, true] defines.LOOKAHEAD = [false, true] @@ -28,8 +28,8 @@ defines.CKMETA = [false, true] defines.CKDATA = [false, true] if = [ 'LFS_IFDEF_CKPROGS(true, !CKPROGS)', - 'LFS_IFDEF_CKREADS(true, !CKREADS)', 'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)', + 'LFS_IFDEF_CKPARITY(true, !CKPARITY)', '!RDONLY || !MKCONSISTENT', '!RDONLY || !LOOKAHEAD', '!RDONLY || !COMPACT', @@ -41,11 +41,11 @@ code = ''' lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, ((RDONLY) ? LFS_M_RDONLY : LFS_M_RDWR) - | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0) - | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_M_CKREADS, -1) : 0) - | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0) | ((FLUSH) ? LFS_M_FLUSH : 0) | ((SYNC) ? LFS_M_SYNC : 0) + | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_M_CKPROGS, -1) : 0) + | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_M_CKFETCHES, -1) : 0) + | ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_M_CKPARITY, -1) : 0) | ((MTREEONLY) ? LFS_M_MTREEONLY : 0) | ((MKCONSISTENT) ? LFS_M_MKCONSISTENT : 0) | ((LOOKAHEAD) ? LFS_M_LOOKAHEAD : 0) @@ -59,11 +59,11 @@ code = ''' lfsr_fs_stat(&lfs, &fsinfo) => 0; assert(fsinfo.flags == ( ((RDONLY) ? LFS_I_RDONLY : 0) - | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_I_CKPROGS, -1) : 0) - | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_I_CKREADS, -1) : 0) - | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_I_CKFETCHES, -1) : 0) | ((FLUSH) ? LFS_I_FLUSH : 0) | ((SYNC) ? LFS_I_SYNC : 0) + | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_I_CKPROGS, -1) : 0) + | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_I_CKFETCHES, -1) : 0) + | ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_I_CKPARITY, -1) : 0) | ((!LOOKAHEAD) ? LFS_I_CANLOOKAHEAD : 0) | ((!COMPACT) ? LFS_I_UNCOMPACTED : 0))); @@ -75,16 +75,16 @@ code = ''' # these end up passed to mount internally [cases.test_mount_format_flags] defines.CKPROGS = [false, true] -defines.CKREADS = [false, true] defines.CKFETCHES = [false, true] +defines.CKPARITY = [false, true] defines.MTREEONLY = [false, true] defines.COMPACT = [false, true] defines.CKMETA = [false, true] defines.CKDATA = [false, true] if = [ 'LFS_IFDEF_CKPROGS(true, !CKPROGS)', - 'LFS_IFDEF_CKREADS(true, !CKREADS)', 'LFS_IFDEF_CKFETCHES(true, !CKFETCHES)', + 'LFS_IFDEF_CKPARITY(true, !CKPARITY)', '!MTREEONLY || !CKDATA', ] code = ''' @@ -92,8 +92,8 @@ code = ''' lfsr_format(&lfs, LFS_F_RDWR | ((CKPROGS) ? LFS_IFDEF_CKPROGS(LFS_F_CKPROGS, -1) : 0) - | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_F_CKREADS, -1) : 0) | ((CKFETCHES) ? LFS_IFDEF_CKFETCHES(LFS_F_CKFETCHES, -1) : 0) + | ((CKPARITY) ? LFS_IFDEF_CKPARITY(LFS_F_CKPARITY, -1) : 0) | ((MTREEONLY) ? LFS_M_MTREEONLY : 0) | ((COMPACT) ? LFS_M_COMPACT : 0) | ((CKMETA) ? LFS_M_CKMETA : 0)