Carved out ckreads, disabled at compile-time by default

This moves all ckread-related logic behind the new opt-in compile-time
LFS_CKREADS flag. So in order to use ckreads you need to 1. define
LFS_CKREADS at compile time, and 2. pass LFS_M_CKREADS during
lfsr_mount.

This was always the plan since, even if ckreads worked perfectly, it
adds a significant amount of baggage (stack mostly) to track the
ck context of all reads.

---

This is the first non-trivial opt-in define in littlefs, so more test
framework features!

test.py and build.py now support the optional ifdef attribute, which
makes it easy to indicate a test suite/case should not be compiled when
a feature is missing.

Also interesting to note is the addition of LFS_IFDEF_CKREADS, which
solves several issues (and general ugliness) related to #ifdefs in
expression. For example:

  // does not compile :( (can't embed ifdefs in macros)
  LFS_ASSERT(flags == (
          LFS_M_CKPROGS
              #ifdef LFS_CKREADS
              | LFS_M_CKREADS
              #endif
              ))

  // does compile :)
  LFS_ASSERT(flags == (
          LFS_M_CKPROGS
              | LFS_IFDEF_CKREADS(LFS_M_CKREADS, 0)));

---

This brings us way back down to our pre-ckread levels of code/stack:

                   code          stack
  before-ckreads: 36352           2672
  ckreads:        38060 (+4.7%)   3056 (+14.4%)
  after-ckreads:  36428 (+0.2%)   2680 (+0.3%)

Unfortunately, we do end up with a bit more code cost than where we
started. Mainly due to code moving around to support the ckread
infrastructure:

                   code          stack
  lfsr_bd_readtag:  +52 (+23.2%)    +8 (+10.0%)
  lfsr_rbyd_fetch:  +36 (+5.0%)     +8 (+6.2%, cold)
  lfs_toleb128:     -12 (-25.0%)    -4 (-20.0%, cold)
  total:            +76 (+0.2%)     +8 (+0.3%)

But oh well. Note that some of these changes are good even without
ckreads, such as only parsing the last ecksum tag.
This commit is contained in:
Christopher Haster
2024-08-11 18:18:28 -05:00
parent 185f209dbf
commit 6e2af5bf80
9 changed files with 352 additions and 53 deletions

256
lfs.c
View File

@@ -695,31 +695,44 @@ static int lfsr_bd_set(lfs_t *lfs, lfs_block_t block, lfs_size_t off,
/// lfsr_ck_t stuff /// /// lfsr_ck_t stuff ///
#ifdef LFS_CKREADS
#define LFSR_CK_ISPARITY 0x80000000 #define LFSR_CK_ISPARITY 0x80000000
#endif
#ifdef LFS_CKREADS
#define LFSR_CK_CKSUM(_cksize, _cksum) \ #define LFSR_CK_CKSUM(_cksize, _cksum) \
((lfsr_ck_t){ \ ((lfsr_ck_t){ \
.cksize=_cksize, \ .cksize=_cksize, \
.u.cksum=_cksum}) .u.cksum=_cksum})
#endif
#ifdef LFS_CKREADS
#define LFSR_CK_PARITY(_ckoff, _cksize) \ #define LFSR_CK_PARITY(_ckoff, _cksize) \
((lfsr_ck_t){ \ ((lfsr_ck_t){ \
.cksize=LFSR_CK_ISPARITY | (_cksize), \ .cksize=LFSR_CK_ISPARITY | (_cksize), \
.u.ckoff=_ckoff}) .u.ckoff=_ckoff})
#endif
// ck helpers // ck helpers
#ifdef LFS_CKREADS
static inline bool lfsr_ck_isparity(lfsr_ck_t ck) { static inline bool lfsr_ck_isparity(lfsr_ck_t ck) {
return ck.cksize & LFSR_CK_ISPARITY; return ck.cksize & LFSR_CK_ISPARITY;
} }
#endif
#ifdef LFS_CKREADS
static inline bool lfsr_ck_iscksum(lfsr_ck_t ck) { static inline bool lfsr_ck_iscksum(lfsr_ck_t ck) {
return !(ck.cksize & LFSR_CK_ISPARITY); return !(ck.cksize & LFSR_CK_ISPARITY);
} }
#endif
#ifdef LFS_CKREADS
static inline lfs_size_t lfsr_ck_cksize(lfsr_ck_t ck) { static inline lfs_size_t lfsr_ck_cksize(lfsr_ck_t ck) {
return ck.cksize & ~LFSR_CK_ISPARITY; return ck.cksize & ~LFSR_CK_ISPARITY;
} }
#endif
#ifdef LFS_CKREADS
static inline lfs_size_t lfsr_ck_ckoff(lfsr_ck_t ck) { static inline lfs_size_t lfsr_ck_ckoff(lfsr_ck_t ck) {
if (lfsr_ck_isparity(ck)) { if (lfsr_ck_isparity(ck)) {
return ck.u.ckoff; return ck.u.ckoff;
@@ -727,22 +740,30 @@ static inline lfs_size_t lfsr_ck_ckoff(lfsr_ck_t ck) {
return 0; return 0;
} }
} }
#endif
// lfsr_tailck_t stuff // lfsr_tailck_t stuff
// //
// tailck tracks the most recent trunk's parity so we can parity-check // tailck tracks the most recent trunk's parity so we can parity-check
// if it hasn't been written to disk yet // if it hasn't been written to disk yet
#ifdef LFS_CKREADS
#define LFSR_TAILCK_PARITY 0x80000000 #define LFSR_TAILCK_PARITY 0x80000000
#endif
#ifdef LFS_CKREADS
static inline bool lfsr_tailck_parity(const lfsr_tailck_t *tailck) { static inline bool lfsr_tailck_parity(const lfsr_tailck_t *tailck) {
return tailck->ckoff & LFSR_TAILCK_PARITY; return tailck->ckoff & LFSR_TAILCK_PARITY;
} }
#endif
#ifdef LFS_CKREADS
static inline lfs_size_t lfsr_tailck_ckoff(const lfsr_tailck_t *tailck) { static inline lfs_size_t lfsr_tailck_ckoff(const lfsr_tailck_t *tailck) {
return tailck->ckoff & ~LFSR_TAILCK_PARITY; return tailck->ckoff & ~LFSR_TAILCK_PARITY;
} }
#endif
#ifdef LFS_CKREADS
// read the pesky parity byte from disk // read the pesky parity byte from disk
static lfs_sbool_t lfsr_bd_readparity(lfs_t *lfs, static lfs_sbool_t lfsr_bd_readparity(lfs_t *lfs,
lfs_block_t block, lfs_size_t off, lfs_size_t hint) { lfs_block_t block, lfs_size_t off, lfs_size_t hint) {
@@ -774,7 +795,9 @@ static lfs_sbool_t lfsr_bd_readparity(lfs_t *lfs,
return p >> 7; return p >> 7;
} }
} }
#endif
#ifdef LFS_CKREADS
static lfs_ssize_t lfsr_bd_ckprefix(lfs_t *lfs, static lfs_ssize_t lfsr_bd_ckprefix(lfs_t *lfs,
lfs_block_t block, lfs_size_t off, lfs_size_t hint, lfs_block_t block, lfs_size_t off, lfs_size_t hint,
lfsr_ck_t ck, lfsr_ck_t ck,
@@ -804,7 +827,9 @@ static lfs_ssize_t lfsr_bd_ckprefix(lfs_t *lfs,
// earlier, otherwise we'd have real problems with hint=-1! // earlier, otherwise we'd have real problems with hint=-1!
return hint_ - (off-lfsr_ck_ckoff(ck)); return hint_ - (off-lfsr_ck_ckoff(ck));
} }
#endif
#ifdef LFS_CKREADS
static int lfsr_bd_cksuffix(lfs_t *lfs, static int lfsr_bd_cksuffix(lfs_t *lfs,
lfs_block_t block, lfs_size_t off, lfs_size_t hint, lfs_block_t block, lfs_size_t off, lfs_size_t hint,
lfsr_ck_t ck, lfsr_ck_t ck,
@@ -861,7 +886,9 @@ static int lfsr_bd_cksuffix(lfs_t *lfs,
return 0; return 0;
} }
#endif
#ifdef LFS_CKREADS
// caching read with parity/checksum checks // caching read with parity/checksum checks
// //
// the main downside of ckreads is we need to read all data that // the main downside of ckreads is we need to read all data that
@@ -906,7 +933,9 @@ static int lfsr_bd_readck_(lfs_t *lfs,
return 0; return 0;
} }
#endif
#ifdef LFS_CKREADS
// needed in lfsr_bd_readck // needed in lfsr_bd_readck
static inline bool lfsr_m_isckreads(uint32_t flags); static inline bool lfsr_m_isckreads(uint32_t flags);
@@ -926,6 +955,16 @@ static int lfsr_bd_readck(lfs_t *lfs,
buffer, size); buffer, size);
} }
} }
#endif
// redirect to lfsr_bd_read if not checking reads
#ifdef LFS_CKREADS
#define LFSR_BD_READCK(_lfs, _block, _off, _hint, _buffer, _size, _ck) \
lfsr_bd_readck(_lfs, _block, _off, _hint, _buffer, _size, _ck)
#else
#define LFSR_BD_READCK(_lfs, _block, _off, _hint, _buffer, _size, _ck) \
lfsr_bd_read(_lfs, _block, _off, _hint, _buffer, _size)
#endif
// these could probably be a bit better deduplicated with their // these could probably be a bit better deduplicated with their
// unchecked counterparts, but we don't generally use both at the same // unchecked counterparts, but we don't generally use both at the same
@@ -933,6 +972,7 @@ static int lfsr_bd_readck(lfs_t *lfs,
// //
// we'd also need to worry about early termination in lfsr_bd_cmp/cmpck // we'd also need to worry about early termination in lfsr_bd_cmp/cmpck
#ifdef LFS_CKREADS
static lfs_scmp_t lfsr_bd_cmpck_(lfs_t *lfs, static lfs_scmp_t lfsr_bd_cmpck_(lfs_t *lfs,
lfs_block_t block, lfs_size_t off, lfs_size_t hint, lfs_block_t block, lfs_size_t off, lfs_size_t hint,
const void *buffer, lfs_size_t size, const void *buffer, lfs_size_t size,
@@ -991,7 +1031,9 @@ static lfs_scmp_t lfsr_bd_cmpck_(lfs_t *lfs,
return cmp; return cmp;
} }
#endif
#ifdef LFS_CKREADS
static lfs_scmp_t lfsr_bd_cmpck(lfs_t *lfs, static lfs_scmp_t lfsr_bd_cmpck(lfs_t *lfs,
lfs_block_t block, lfs_size_t off, lfs_size_t hint, lfs_block_t block, lfs_size_t off, lfs_size_t hint,
const void *buffer, lfs_size_t size, const void *buffer, lfs_size_t size,
@@ -1008,7 +1050,18 @@ static lfs_scmp_t lfsr_bd_cmpck(lfs_t *lfs,
buffer, size); buffer, size);
} }
} }
#endif
// redirect to lfsr_bd_cmp if not checking reads
#ifdef LFS_CKREADS
#define LFSR_BD_CMPCK(_lfs, _block, _off, _hint, _buffer, _size, _ck) \
lfsr_bd_cmpck(_lfs, _block, _off, _hint, _buffer, _size, _ck)
#else
#define LFSR_BD_CMPCK(_lfs, _block, _off, _hint, _buffer, _size, _ck) \
lfsr_bd_cmp(_lfs, _block, _off, _hint, _buffer, _size)
#endif
#ifdef LFS_CKREADS
static int lfsr_bd_cpyck_(lfs_t *lfs, static int lfsr_bd_cpyck_(lfs_t *lfs,
lfs_block_t dst_block, lfs_size_t dst_off, 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_block_t src_block, lfs_size_t src_off, lfs_size_t hint,
@@ -1080,7 +1133,9 @@ static int lfsr_bd_cpyck_(lfs_t *lfs,
return 0; return 0;
} }
#endif
#ifdef LFS_CKREADS
static int lfsr_bd_cpyck(lfs_t *lfs, static int lfsr_bd_cpyck(lfs_t *lfs,
lfs_block_t dst_block, lfs_size_t dst_off, 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_block_t src_block, lfs_size_t src_off, lfs_size_t hint,
@@ -1103,6 +1158,35 @@ static int lfsr_bd_cpyck(lfs_t *lfs,
cksum, align); cksum, align);
} }
} }
#endif
// redirect to lfsr_bd_cpy if not checking reads
#ifdef LFS_CKREADS
#define LFSR_BD_CPYCK(_lfs, \
_dst_block, _dst_off, \
_src_block, _src_off, _hint, \
_size, \
_ck, \
_cksum, _align) \
lfsr_bd_cpyck(_lfs, \
_dst_block, _dst_off, \
_src_block, _src_off, _hint, \
_size, \
_ck, \
_cksum, _align)
#else
#define LFSR_BD_CPYCK(_lfs, \
_dst_block, _dst_off, \
_src_block, _src_off, _hint, \
_size, \
_ck, \
_cksum, _align) \
lfsr_bd_cpy(_lfs, \
_dst_block, _dst_off, \
_src_block, _src_off, _hint, \
_size, \
_cksum, _align)
#endif
@@ -1625,6 +1709,7 @@ static lfs_ssize_t lfsr_bd_readtag(lfs_t *lfs,
*cksum = lfs_crc32c(*cksum, tag_buf, d); *cksum = lfs_crc32c(*cksum, tag_buf, d);
} }
#ifdef LFS_CKREADS
// check the parity if we're checking reads and not already // check the parity if we're checking reads and not already
// calculating a checksum // calculating a checksum
// //
@@ -1649,6 +1734,7 @@ static lfs_ssize_t lfsr_bd_readtag(lfs_t *lfs,
return err; return err;
} }
} }
#endif
// save what we found, clearing the valid bit, we don't need it // save what we found, clearing the valid bit, we don't need it
// anymore // anymore
@@ -1720,28 +1806,35 @@ static lfs_ssize_t lfsr_bd_progtag(lfs_t *lfs,
.size=_size, \ .size=_size, \
.u.buffer=(const void*)(_buffer)}) .u.buffer=(const void*)(_buffer)})
// TODO #ifdef LFS_CKREADS
#if 0
#define LFSR_DATA_DISK(_block, _off, _size) \
((lfsr_data_t){ \
.size=LFSR_DATA_ONDISK | (_size), \
.u.disk.block=_block, \
.u.disk.off=_off})
#endif
#define LFSR_DATA_DISKCKSUM(_block, _off, _size, _cksize, _cksum) \ #define LFSR_DATA_DISKCKSUM(_block, _off, _size, _cksize, _cksum) \
((lfsr_data_t){ \ ((lfsr_data_t){ \
.size=LFSR_DATA_ONDISK | (_size), \ .size=LFSR_DATA_ONDISK | (_size), \
.u.disk.block=_block, \ .u.disk.block=_block, \
.u.disk.off=_off, \ .u.disk.off=_off, \
.u.disk.ck=LFSR_CK_CKSUM(_cksize, _cksum)}) .u.disk.ck=LFSR_CK_CKSUM(_cksize, _cksum)})
#else
#define LFSR_DATA_DISKCKSUM(_block, _off, _size, _cksize, _cksum) \
((lfsr_data_t){ \
.size=LFSR_DATA_ONDISK | (_size), \
.u.disk.block=_block, \
.u.disk.off=_off})
#endif
#ifdef LFS_CKREADS
#define LFSR_DATA_DISKPARITY(_block, _off, _size, _ckoff, _cksize) \ #define LFSR_DATA_DISKPARITY(_block, _off, _size, _ckoff, _cksize) \
((lfsr_data_t){ \ ((lfsr_data_t){ \
.size=LFSR_DATA_ONDISK | (_size), \ .size=LFSR_DATA_ONDISK | (_size), \
.u.disk.block=_block, \ .u.disk.block=_block, \
.u.disk.off=_off, \ .u.disk.off=_off, \
.u.disk.ck=LFSR_CK_PARITY(_ckoff, _cksize)}) .u.disk.ck=LFSR_CK_PARITY(_ckoff, _cksize)})
#else
#define LFSR_DATA_DISKPARITY(_block, _off, _size, _ckoff, _cksize) \
((lfsr_data_t){ \
.size=LFSR_DATA_ONDISK | (_size), \
.u.disk.block=_block, \
.u.disk.off=_off})
#endif
// data helpers // data helpers
static inline bool lfsr_data_ondisk(lfsr_data_t data) { static inline bool lfsr_data_ondisk(lfsr_data_t data) {
@@ -1806,7 +1899,7 @@ static lfs_ssize_t lfsr_data_read(lfs_t *lfs, lfsr_data_t *data,
// on-disk? // on-disk?
if (lfsr_data_ondisk(*data)) { if (lfsr_data_ondisk(*data)) {
int err = lfsr_bd_readck(lfs, int err = LFSR_BD_READCK(lfs,
data->u.disk.block, data->u.disk.off, data->u.disk.block, data->u.disk.off,
// note our hint includes the full data range // note our hint includes the full data range
lfsr_data_size(*data), lfsr_data_size(*data),
@@ -1895,7 +1988,7 @@ static lfs_scmp_t lfsr_data_cmp(lfs_t *lfs, lfsr_data_t data,
// on-disk? // on-disk?
if (lfsr_data_ondisk(data)) { if (lfsr_data_ondisk(data)) {
int cmp = lfsr_bd_cmpck(lfs, int cmp = LFSR_BD_CMPCK(lfs,
// note the 0 hint, we don't usually use any following data // note the 0 hint, we don't usually use any following data
data.u.disk.block, data.u.disk.off, 0, data.u.disk.block, data.u.disk.off, 0,
buffer, d, buffer, d,
@@ -1948,7 +2041,7 @@ static int lfsr_bd_progdata(lfs_t *lfs,
uint32_t *cksum, bool align) { uint32_t *cksum, bool align) {
// on-disk? // on-disk?
if (lfsr_data_ondisk(data)) { if (lfsr_data_ondisk(data)) {
int err = lfsr_bd_cpyck(lfs, block, off, int err = LFSR_BD_CPYCK(lfs, block, off,
data.u.disk.block, data.u.disk.off, lfsr_data_size(data), data.u.disk.block, data.u.disk.off, lfsr_data_size(data),
lfsr_data_size(data), lfsr_data_size(data),
data.u.disk.ck, data.u.disk.ck,
@@ -2386,6 +2479,25 @@ static int lfsr_data_readecksum(lfs_t *lfs, lfsr_data_t *data,
#define LFSR_DATA_BPTR(_bptr) \ #define LFSR_DATA_BPTR(_bptr) \
LFSR_DATA_BPTR_(_bptr, (uint8_t[LFSR_BPTR_DSIZE]){0}) 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...
static inline lfs_size_t lfsr_bptr_cksize(const lfsr_bptr_t *bptr) {
#ifdef LFS_CKREADS
return bptr->data.u.disk.ck.cksize;
#else
return bptr->cksize;
#endif
}
static inline uint32_t lfsr_bptr_cksum(const lfsr_bptr_t *bptr) {
#ifdef LFS_CKREADS
return bptr->data.u.disk.ck.u.cksum;
#else
return bptr->cksum;
#endif
}
static lfsr_data_t lfsr_data_frombptr(const lfsr_bptr_t *bptr, static lfsr_data_t lfsr_data_frombptr(const lfsr_bptr_t *bptr,
uint8_t buffer[static LFSR_BPTR_DSIZE]) { uint8_t buffer[static LFSR_BPTR_DSIZE]) {
// size should not exceed 28-bits // size should not exceed 28-bits
@@ -2395,7 +2507,7 @@ static lfsr_data_t lfsr_data_frombptr(const lfsr_bptr_t *bptr,
// off should not exceed 28-bits // off should not exceed 28-bits
LFS_ASSERT(bptr->data.u.disk.off <= 0x0fffffff); LFS_ASSERT(bptr->data.u.disk.off <= 0x0fffffff);
// cksize should not exceed 28-bits // cksize should not exceed 28-bits
LFS_ASSERT(bptr->data.u.disk.ck.cksize <= 0x0fffffff); LFS_ASSERT(lfsr_bptr_cksize(bptr) <= 0x0fffffff);
lfs_ssize_t d = 0; lfs_ssize_t d = 0;
// write the block, offset, size // write the block, offset, size
@@ -2418,13 +2530,13 @@ static lfsr_data_t lfsr_data_frombptr(const lfsr_bptr_t *bptr,
d += d_; d += d_;
// write the cksize, cksum // write the cksize, cksum
d_ = lfs_toleb128(bptr->data.u.disk.ck.cksize, &buffer[d], 4); d_ = lfs_toleb128(lfsr_bptr_cksize(bptr), &buffer[d], 4);
if (d_ < 0) { if (d_ < 0) {
LFS_UNREACHABLE(); LFS_UNREACHABLE();
} }
d += d_; d += d_;
lfs_tole32_(bptr->data.u.disk.ck.u.cksum, &buffer[d]); lfs_tole32_(lfsr_bptr_cksum(bptr), &buffer[d]);
d += 4; d += 4;
return LFSR_DATA_BUF(buffer, d); return LFSR_DATA_BUF(buffer, d);
@@ -2449,12 +2561,18 @@ static int lfsr_data_readbptr(lfs_t *lfs, lfsr_data_t *data,
} }
// read the cksize, cksum // read the cksize, cksum
err = lfsr_data_readlleb128(lfs, data, &bptr->data.u.disk.ck.cksize); err = lfsr_data_readlleb128(lfs, data,
LFS_IFDEF_CKREADS(
&bptr->data.u.disk.ck.cksize,
&bptr->cksize));
if (err) { if (err) {
return err; return err;
} }
err = lfsr_data_readle32(lfs, data, &bptr->data.u.disk.ck.u.cksum); err = lfsr_data_readle32(lfs, data,
LFS_IFDEF_CKREADS(
&bptr->data.u.disk.ck.u.cksum,
&bptr->cksum));
if (err) { if (err) {
return err; return err;
} }
@@ -2470,20 +2588,20 @@ static int lfsr_bptr_ck(lfs_t *lfs, const lfsr_bptr_t *bptr) {
uint32_t cksum = 0; uint32_t cksum = 0;
int err = lfsr_bd_cksum(lfs, int err = lfsr_bd_cksum(lfs,
bptr->data.u.disk.block, 0, 0, bptr->data.u.disk.block, 0, 0,
bptr->data.u.disk.ck.cksize, lfsr_bptr_cksize(bptr),
&cksum); &cksum);
if (err) { if (err) {
return err; return err;
} }
// test that our cksum matches what's expected // test that our cksum matches what's expected
if (cksum != bptr->data.u.disk.ck.u.cksum) { if (cksum != lfsr_bptr_cksum(bptr)) {
LFS_ERROR("Found bptr cksum mismatch " LFS_ERROR("Found bptr cksum mismatch "
"0x%"PRIx32".%"PRIx32" %"PRId32", " "0x%"PRIx32".%"PRIx32" %"PRId32", "
"cksum %08"PRIx32" (!= %08"PRIx32")", "cksum %08"PRIx32" (!= %08"PRIx32")",
bptr->data.u.disk.block, 0, bptr->data.u.disk.block, 0,
bptr->data.u.disk.ck.cksize, lfsr_bptr_cksize(bptr),
cksum, bptr->data.u.disk.ck.u.cksum); cksum, lfsr_bptr_cksum(bptr));
return LFS_ERR_CORRUPT; return LFS_ERR_CORRUPT;
} }
@@ -3125,6 +3243,7 @@ static int lfsr_rbyd_appendtag(lfs_t *lfs, lfsr_rbyd_t *rbyd,
rbyd->eoff += d; rbyd->eoff += d;
#ifdef LFS_CKREADS
// keep track of most recent parity // keep track of most recent parity
lfs->tailck.ckblock = rbyd->blocks[0]; lfs->tailck.ckblock = rbyd->blocks[0];
lfs->tailck.ckoff lfs->tailck.ckoff
@@ -3132,6 +3251,7 @@ static int lfsr_rbyd_appendtag(lfs_t *lfs, lfsr_rbyd_t *rbyd,
lfs_parity(rbyd->cksum) ^ lfsr_rbyd_isperturb(rbyd) lfs_parity(rbyd->cksum) ^ lfsr_rbyd_isperturb(rbyd)
) << (8*sizeof(lfs_size_t)-1)) ) << (8*sizeof(lfs_size_t)-1))
| lfsr_rbyd_eoff(rbyd); | lfsr_rbyd_eoff(rbyd);
#endif
return 0; return 0;
} }
@@ -3154,6 +3274,7 @@ static int lfsr_rbyd_appendcat(lfs_t *lfs, lfsr_rbyd_t *rbyd,
rbyd->eoff += lfsr_cat_size(cat, count); rbyd->eoff += lfsr_cat_size(cat, count);
#ifdef LFS_CKREADS
// keep track of most recent parity // keep track of most recent parity
lfs->tailck.ckblock = rbyd->blocks[0]; lfs->tailck.ckblock = rbyd->blocks[0];
lfs->tailck.ckoff lfs->tailck.ckoff
@@ -3161,6 +3282,7 @@ static int lfsr_rbyd_appendcat(lfs_t *lfs, lfsr_rbyd_t *rbyd,
lfs_parity(rbyd->cksum) ^ lfsr_rbyd_isperturb(rbyd) lfs_parity(rbyd->cksum) ^ lfsr_rbyd_isperturb(rbyd)
) << (8*sizeof(lfs_size_t)-1)) ) << (8*sizeof(lfs_size_t)-1))
| lfsr_rbyd_eoff(rbyd); | lfsr_rbyd_eoff(rbyd);
#endif
return 0; return 0;
} }
@@ -6565,9 +6687,11 @@ static inline bool lfsr_m_isckprogs(uint32_t flags) {
return flags & LFS_M_CKPROGS; return flags & LFS_M_CKPROGS;
} }
#ifdef LFS_CKREADS
static inline bool lfsr_m_isckreads(uint32_t flags) { static inline bool lfsr_m_isckreads(uint32_t flags) {
return flags & LFS_M_CKREADS; return flags & LFS_M_CKREADS;
} }
#endif
static inline bool lfsr_m_isflush(uint32_t flags) { static inline bool lfsr_m_isflush(uint32_t flags) {
return flags & LFS_M_FLUSH; return flags & LFS_M_FLUSH;
@@ -7260,7 +7384,7 @@ static int lfsr_mdir_swap__(lfs_t *lfs, lfsr_mdir_t *mdir_,
// first thing we need to do is read our current revision count // first thing we need to do is read our current revision count
uint32_t rev; uint32_t rev;
int err = lfsr_bd_readck(lfs, mdir->rbyd.blocks[0], 0, 0, int err = LFSR_BD_READCK(lfs, mdir->rbyd.blocks[0], 0, 0,
&rev, sizeof(uint32_t), &rev, sizeof(uint32_t),
LFSR_CK_PARITY(0, sizeof(uint32_t))); LFSR_CK_PARITY(0, sizeof(uint32_t)));
if (err && err != LFS_ERR_CORRUPT) { if (err && err != LFS_ERR_CORRUPT) {
@@ -11051,7 +11175,13 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_BLOCK, LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_BLOCK,
-(bid+1 - pos), -(bid+1 - pos),
LFSR_DATA_BPTR_( LFSR_DATA_BPTR_(
(&(lfsr_bptr_t){.data=left_slice_}), LFS_IFDEF_CKREADS(
(&(lfsr_bptr_t){
.data=left_slice_}),
(&(lfsr_bptr_t){
.data=left_slice_,
.cksize=bptr_.cksize,
.cksum=bptr_.cksum})),
left.buf)); left.buf));
} else { } else {
@@ -11103,7 +11233,13 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
tag_, tag_,
bid+1 - (pos+weight), bid+1 - (pos+weight),
LFSR_DATA_BPTR_( LFSR_DATA_BPTR_(
(&(lfsr_bptr_t){.data=right_slice_}), LFS_IFDEF_CKREADS(
(&(lfsr_bptr_t){
.data=right_slice_}),
(&(lfsr_bptr_t){
.data=right_slice_,
.cksize=bptr_.cksize,
.cksum=bptr_.cksum})),
right.buf)); right.buf));
} else { } else {
@@ -11343,6 +11479,12 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
} }
bptr.data = LFSR_DATA_DISKCKSUM(block, 0, 0, 0, 0); bptr.data = LFSR_DATA_DISKCKSUM(block, 0, 0, 0, 0);
LFS_IFDEF_CKREADS(
bptr.data.u.disk.ck.cksize,
bptr.cksize) = 0;
LFS_IFDEF_CKREADS(
bptr.data.u.disk.ck.u.cksum,
bptr.cksum) = 0;
compact:; compact:;
// compact data into our block // compact data into our block
@@ -11371,9 +11513,11 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
d, d,
size - (pos_ - pos)); size - (pos_ - pos));
int err = lfsr_bd_prog(lfs, bptr.data.u.disk.block, int err = lfsr_bd_prog(lfs, bptr.data.u.disk.block,
bptr.data.u.disk.ck.cksize, lfsr_bptr_cksize(&bptr),
&buffer[pos_ - pos], d_, &buffer[pos_ - pos], d_,
&bptr.data.u.disk.ck.u.cksum, true); LFS_IFDEF_CKREADS(
&bptr.data.u.disk.ck.u.cksum,
&bptr.cksum), true);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
// bad prog? try another block // bad prog? try another block
@@ -11384,7 +11528,9 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
} }
pos_ += d_; pos_ += d_;
bptr.data.u.disk.ck.cksize += d_; LFS_IFDEF_CKREADS(
bptr.data.u.disk.ck.cksize,
bptr.cksize) += d_;
d -= d_; d -= d_;
} }
@@ -11430,11 +11576,13 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
lfsr_data_size(bptr_.data) lfsr_data_size(bptr_.data)
- (pos_ - (bid_-(weight_-1)))); - (pos_ - (bid_-(weight_-1))));
err = lfsr_bd_progdata(lfs, bptr.data.u.disk.block, err = lfsr_bd_progdata(lfs, bptr.data.u.disk.block,
bptr.data.u.disk.ck.cksize, lfsr_bptr_cksize(&bptr),
lfsr_data_slice(bptr_.data, lfsr_data_slice(bptr_.data,
pos_ - (bid_-(weight_-1)), pos_ - (bid_-(weight_-1)),
d_), d_),
&bptr.data.u.disk.ck.u.cksum, true); LFS_IFDEF_CKREADS(
&bptr.data.u.disk.ck.u.cksum,
&bptr.cksum), true);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
// bad prog? try another block // bad prog? try another block
@@ -11445,7 +11593,9 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
} }
pos_ += d_; pos_ += d_;
bptr.data.u.disk.ck.cksize += d_; LFS_IFDEF_CKREADS(
bptr.data.u.disk.ck.cksize,
bptr.cksize) += d_;
d -= d_; d -= d_;
} }
@@ -11455,9 +11605,11 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
// found a hole? fill with zeros // found a hole? fill with zeros
int err = lfsr_bd_set(lfs, int err = lfsr_bd_set(lfs,
bptr.data.u.disk.block, bptr.data.u.disk.ck.cksize, bptr.data.u.disk.block, lfsr_bptr_cksize(&bptr),
0, d, 0, d,
&bptr.data.u.disk.ck.u.cksum, true); LFS_IFDEF_CKREADS(
&bptr.data.u.disk.ck.u.cksum,
&bptr.cksum), true);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
// bad prog? try another block // bad prog? try another block
@@ -11468,19 +11620,25 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
} }
pos_ += d; pos_ += d;
bptr.data.u.disk.ck.cksize += d; LFS_IFDEF_CKREADS(
bptr.data.u.disk.ck.cksize,
bptr.cksize) += d;
} }
// A bit of a hack here, we need to truncate our block to prog_size // A bit of a hack here, we need to truncate our block to prog_size
// alignment to avoid padding issues. Doing this retroactively to // alignment to avoid padding issues. Doing this retroactively to
// the pcache greatly simplifies the above loop, though we may end // the pcache greatly simplifies the above loop, though we may end
// up reading more than is strictly necessary. // up reading more than is strictly necessary.
lfs_ssize_t d = bptr.data.u.disk.ck.cksize % lfs->cfg->prog_size; lfs_ssize_t d = lfsr_bptr_cksize(&bptr) % lfs->cfg->prog_size;
lfs->pcache.size -= d; lfs->pcache.size -= d;
bptr.data.u.disk.ck.cksize -= d; LFS_IFDEF_CKREADS(
bptr.data.u.disk.ck.cksize,
bptr.cksize) -= d;
// finalize our write // finalize our write
int err = lfsr_bd_flush(lfs, &bptr.data.u.disk.ck.u.cksum, true); int err = lfsr_bd_flush(lfs, LFS_IFDEF_CKREADS(
&bptr.data.u.disk.ck.u.cksum,
&bptr.cksum), true);
if (err) { if (err) {
// bad prog? try another block // bad prog? try another block
if (err == LFS_ERR_CORRUPT) { if (err == LFS_ERR_CORRUPT) {
@@ -11490,14 +11648,14 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
} }
// prepare our block pointer // prepare our block pointer
LFS_ASSERT(bptr.data.u.disk.ck.cksize > 0); LFS_ASSERT(lfsr_bptr_cksize(&bptr) > 0);
LFS_ASSERT(bptr.data.u.disk.ck.cksize <= lfs->cfg->block_size); LFS_ASSERT(lfsr_bptr_cksize(&bptr) <= lfs->cfg->block_size);
bptr.data = LFSR_DATA_DISKCKSUM( bptr.data = LFSR_DATA_DISKCKSUM(
bptr.data.u.disk.block, bptr.data.u.disk.block,
bptr.data.u.disk.off, bptr.data.u.disk.off,
bptr.data.u.disk.ck.cksize - bptr.data.u.disk.off, lfsr_bptr_cksize(&bptr) - bptr.data.u.disk.off,
bptr.data.u.disk.ck.cksize, lfsr_bptr_cksize(&bptr),
bptr.data.u.disk.ck.u.cksum); lfsr_bptr_cksum(&bptr));
lfs_off_t block_end = block_start + lfsr_data_size(bptr.data); lfs_off_t block_end = block_start + lfsr_data_size(bptr.data);
// and write it into our tree // and write it into our tree
@@ -11512,9 +11670,9 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
} }
// keep track of any remaining erased-state // keep track of any remaining erased-state
if (bptr.data.u.disk.ck.cksize < lfs->cfg->block_size) { if (lfsr_bptr_cksize(&bptr) < lfs->cfg->block_size) {
file->eblock = bptr.data.u.disk.block; file->eblock = bptr.data.u.disk.block;
file->eoff = bptr.data.u.disk.ck.cksize; file->eoff = lfsr_bptr_cksize(&bptr);
} }
// note compacting fragments -> blocks may not actually make any // note compacting fragments -> blocks may not actually make any
@@ -12476,9 +12634,11 @@ static int lfs_init(lfs_t *lfs, uint32_t flags,
} }
} }
#ifdef LFS_CKREADS
// setup tailck, nothing should actually check off=0 // setup tailck, nothing should actually check off=0
lfs->tailck.ckblock = 0; lfs->tailck.ckblock = 0;
lfs->tailck.ckoff = 0; lfs->tailck.ckoff = 0;
#endif
// setup lookahead buffer, note mount finishes initializing this after // setup lookahead buffer, note mount finishes initializing this after
// we establish a decent pseudo-random seed // we establish a decent pseudo-random seed
@@ -13184,7 +13344,7 @@ int lfsr_mount(lfs_t *lfs, uint32_t flags,
LFS_M_RDWR LFS_M_RDWR
| LFS_M_RDONLY | LFS_M_RDONLY
| LFS_M_CKPROGS | LFS_M_CKPROGS
| LFS_M_CKREADS | LFS_IFDEF_CKREADS(LFS_M_CKREADS, 0)
| LFS_M_FLUSH | LFS_M_FLUSH
| LFS_M_SYNC | LFS_M_SYNC
| LFS_M_MTREEONLY | LFS_M_MTREEONLY
@@ -13342,7 +13502,11 @@ static int lfsr_formatinited(lfs_t *lfs) {
int lfsr_format(lfs_t *lfs, const struct lfs_config *cfg) { int lfsr_format(lfs_t *lfs, const struct lfs_config *cfg) {
// TODO hmmm, should lfsr_format take flags? // TODO hmmm, should lfsr_format take flags?
int err = lfs_init(lfs, LFS_M_RDWR | LFS_M_CKPROGS | LFS_M_CKREADS, cfg); int err = lfs_init(lfs,
LFS_M_RDWR
| LFS_M_CKPROGS
| LFS_IFDEF_CKREADS(LFS_M_CKREADS, 0),
cfg);
if (err) { if (err) {
return err; return err;
} }
@@ -13373,7 +13537,7 @@ int lfsr_fs_stat(lfs_t *lfs, struct lfs_fsinfo *fsinfo) {
fsinfo->flags = lfs->flags & ( fsinfo->flags = lfs->flags & (
LFS_I_RDONLY LFS_I_RDONLY
| LFS_I_CKPROGS | LFS_I_CKPROGS
| LFS_I_CKREADS | LFS_IFDEF_CKREADS(LFS_I_CKREADS, 0)
| LFS_I_FLUSH | LFS_I_FLUSH
| LFS_I_SYNC | LFS_I_SYNC
| LFS_I_UNCOMPACTED); | LFS_I_UNCOMPACTED);

16
lfs.h
View File

@@ -155,7 +155,9 @@ enum lfs_type {
#define LFS_M_RDWR 0 // Mount the filesystem as read and write #define LFS_M_RDWR 0 // Mount the filesystem as read and write
#define LFS_M_RDONLY 1 // Mount the filesystem as read only #define LFS_M_RDONLY 1 // Mount the filesystem as read only
#define LFS_M_CKPROGS 0x00000010 // Check progs by reading back progged data #define LFS_M_CKPROGS 0x00000010 // Check progs by reading back progged data
#ifdef LFS_CKREADS
#define LFS_M_CKREADS 0x00000020 // Check reads via parity bits/checksums #define LFS_M_CKREADS 0x00000020 // Check reads via parity bits/checksums
#endif
#define LFS_M_FLUSH 0x00000040 // Open all files with LFS_O_FLUSH #define LFS_M_FLUSH 0x00000040 // Open all files with LFS_O_FLUSH
#define LFS_M_SYNC 0x00000080 // Open all files with LFS_O_SYNC #define LFS_M_SYNC 0x00000080 // Open all files with LFS_O_SYNC
@@ -177,7 +179,9 @@ enum lfs_type {
// Filesystem info flags // Filesystem info flags
#define LFS_I_RDONLY 0x00000001 // Filesystem mounted read only #define LFS_I_RDONLY 0x00000001 // Filesystem mounted read only
#define LFS_I_CKPROGS 0x00000010 // Filesystem mounted with LFS_M_CKPROGS #define LFS_I_CKPROGS 0x00000010 // Filesystem mounted with LFS_M_CKPROGS
#ifdef LFS_CKREADS
#define LFS_I_CKREADS 0x00000020 // Filesystem mounted with LFS_M_CKREADS #define LFS_I_CKREADS 0x00000020 // Filesystem mounted with LFS_M_CKREADS
#endif
#define LFS_I_FLUSH 0x00000040 // Filesystem mounted with LFS_M_FLUSH #define LFS_I_FLUSH 0x00000040 // Filesystem mounted with LFS_M_FLUSH
#define LFS_I_SYNC 0x00000080 // Filesystem mounted with LFS_M_SYNC #define LFS_I_SYNC 0x00000080 // Filesystem mounted with LFS_M_SYNC
@@ -536,6 +540,7 @@ typedef struct lfsr_omdir {
// lfs_block_t tail[2]; // lfs_block_t tail[2];
//} lfs_mdir_t; //} lfs_mdir_t;
#ifdef LFS_CKREADS
// context for validating data // context for validating data
typedef struct lfsr_ck { typedef struct lfsr_ck {
// sign(cksize)=0 => cksum check // sign(cksize)=0 => cksum check
@@ -546,6 +551,7 @@ typedef struct lfsr_ck {
uint32_t cksum; uint32_t cksum;
} u; } u;
} lfsr_ck_t; } lfsr_ck_t;
#endif
// either an on-disk or in-device data pointer // either an on-disk or in-device data pointer
typedef struct lfsr_data { typedef struct lfsr_data {
@@ -557,7 +563,9 @@ typedef struct lfsr_data {
struct { struct {
lfs_block_t block; lfs_block_t block;
lfs_size_t off; lfs_size_t off;
#ifdef LFS_CKREADS
lfsr_ck_t ck; lfsr_ck_t ck;
#endif
} disk; } disk;
} u; } u;
} lfsr_data_t; } lfsr_data_t;
@@ -588,6 +596,10 @@ typedef lfsr_data_t lfsr_sprout_t;
typedef struct lfsr_bptr { typedef struct lfsr_bptr {
lfsr_data_t data; lfsr_data_t data;
#ifndef LFS_CKREADS
lfs_size_t cksize;
uint32_t cksum;
#endif
} lfsr_bptr_t; } lfsr_bptr_t;
// the lfsr_bshrub_t struct represents the on-disk component of a file // the lfsr_bshrub_t struct represents the on-disk component of a file
@@ -726,11 +738,13 @@ typedef struct lfsr_grm {
lfsr_smid_t mids[2]; lfsr_smid_t mids[2];
} lfsr_grm_t; } lfsr_grm_t;
#ifdef LFS_CKREADS
typedef struct lfsr_tailck { typedef struct lfsr_tailck {
lfs_block_t ckblock; lfs_block_t ckblock;
// sign(ckoff) => tail parity // sign(ckoff) => tail parity
lfs_size_t ckoff; lfs_size_t ckoff;
} lfsr_tailck_t; } lfsr_tailck_t;
#endif
// The littlefs filesystem type // The littlefs filesystem type
typedef struct lfs { typedef struct lfs {
@@ -764,7 +778,9 @@ typedef struct lfs {
uint8_t *buffer; uint8_t *buffer;
} pcache; } pcache;
#ifdef LFS_CKREADS
lfsr_tailck_t tailck; lfsr_tailck_t tailck;
#endif
struct lfs_lookahead { struct lfs_lookahead {
lfs_block_t window; lfs_block_t window;

View File

@@ -137,6 +137,14 @@ extern "C"
#endif #endif
// Some ifdef conveniences
#ifdef LFS_CKREADS
#define LFS_IFDEF_CKREADS(a, b) a
#else
#define LFS_IFDEF_CKREADS(a, b) b
#endif
// Builtin functions, these may be replaced by more efficient // Builtin functions, these may be replaced by more efficient
// toolchain-specific implementations. LFS_NO_BUILTINS falls back to a more // toolchain-specific implementations. LFS_NO_BUILTINS falls back to a more
// expensive basic C implementation for debugging purposes // expensive basic C implementation for debugging purposes

View File

@@ -849,7 +849,7 @@ void perm_count(
state->total += 1; state->total += 1;
if (!bench_all && case_->if_ && !case_->if_()) { if (!case_->run || !(bench_all || !case_->if_ || case_->if_())) {
return; return;
} }
@@ -1334,7 +1334,7 @@ void perm_run(
bench_step += 1; bench_step += 1;
// filter? // filter?
if (!bench_all && case_->if_ && !case_->if_()) { if (!case_->run || !(bench_all || !case_->if_ || case_->if_())) {
printf("skipped "); printf("skipped ");
perm_printid(suite, case_); perm_printid(suite, case_);
printf("\n"); printf("\n");

View File

@@ -812,7 +812,7 @@ void perm_count(
// set pls to 1 if running under powerloss so it useful for if predicates // set pls to 1 if running under powerloss so it useful for if predicates
TEST_PLS = (powerloss->run != run_powerloss_none); TEST_PLS = (powerloss->run != run_powerloss_none);
if (!test_all && case_->if_ && !case_->if_()) { if (!case_->run || !(test_all || !case_->if_ || case_->if_())) {
return; return;
} }
@@ -1808,7 +1808,7 @@ void perm_run(
// set pls to 1 if running under powerloss so it useful for if predicates // set pls to 1 if running under powerloss so it useful for if predicates
TEST_PLS = (powerloss->run != run_powerloss_none); TEST_PLS = (powerloss->run != run_powerloss_none);
// filter? // filter?
if (!test_all && case_->if_ && !case_->if_()) { if (!case_->run || !(test_all || !case_->if_ || case_->if_())) {
printf("skipped "); printf("skipped ");
perm_printid(suite, case_, NULL, 0); perm_printid(suite, case_, NULL, 0);
printf("\n"); printf("\n");

View File

@@ -55,6 +55,9 @@ class BenchCase:
self.if_ = config.pop('if', []) self.if_ = config.pop('if', [])
if not isinstance(self.if_, list): if not isinstance(self.if_, list):
self.if_ = [self.if_] self.if_ = [self.if_]
self.ifdef = config.pop('ifdef', [])
if not isinstance(self.ifdef, list):
self.ifdef = [self.ifdef]
self.code = config.pop('code') self.code = config.pop('code')
self.code_lineno = config.pop('code_lineno', None) self.code_lineno = config.pop('code_lineno', None)
self.in_ = config.pop('in', self.in_ = config.pop('in',
@@ -199,6 +202,10 @@ class BenchSuite:
if not isinstance(self.if_, list): if not isinstance(self.if_, list):
self.if_ = [self.if_] self.if_ = [self.if_]
self.ifdef = config.pop('ifdef', [])
if not isinstance(self.ifdef, list):
self.ifdef = [self.ifdef]
self.code = config.pop('code', None) self.code = config.pop('code', None)
self.code_lineno = min( self.code_lineno = min(
(l for l in code_linenos (l for l in code_linenos
@@ -357,6 +364,12 @@ def compile(bench_paths, **args):
# note it's up to the specific generated file to declare # note it's up to the specific generated file to declare
# the bench defines # the bench defines
def write_case_functions(f, suite, case): def write_case_functions(f, suite, case):
# write any ifdef prologues
if case.ifdef:
for ifdef in case.ifdef:
f.writeln('#ifdef %s' % ifdef)
f.writeln()
# create case define functions # create case define functions
for i, permutation in enumerate(case.permutations): for i, permutation in enumerate(case.permutations):
for k, vs in sorted(permutation.items()): for k, vs in sorted(permutation.items()):
@@ -413,7 +426,19 @@ def compile(bench_paths, **args):
f.writeln('}') f.writeln('}')
f.writeln() f.writeln()
# write any ifdef epilogues
if case.ifdef:
for ifdef in case.ifdef:
f.writeln('#endif')
f.writeln()
if not args.get('source'): if not args.get('source'):
# write any ifdef prologues
if suite.ifdef:
for ifdef in suite.ifdef:
f.writeln('#ifdef %s' % ifdef)
f.writeln()
# write any suite defines # write any suite defines
if suite.defines: if suite.defines:
for define in sorted(suite.defines): for define in sorted(suite.defines):
@@ -451,6 +476,12 @@ def compile(bench_paths, **args):
% (case.name)) % (case.name))
f.writeln() f.writeln()
# write any ifdef epilogues
if suite.ifdef:
for ifdef in suite.ifdef:
f.writeln('#endif')
f.writeln()
# create suite struct # create suite struct
f.writeln('const struct bench_suite __bench__%s__suite = {' f.writeln('const struct bench_suite __bench__%s__suite = {'
% suite.name) % suite.name)
@@ -460,6 +491,8 @@ def compile(bench_paths, **args):
% (' | '.join(filter(None, [ % (' | '.join(filter(None, [
'BENCH_INTERNAL' if suite.internal else None])) 'BENCH_INTERNAL' if suite.internal else None]))
or 0)) or 0))
for ifdef in suite.ifdef:
f.writeln(4*' '+'#ifdef %s' % ifdef)
# create suite defines # create suite defines
if suite.defines: if suite.defines:
f.writeln(4*' '+'.defines = (const bench_define_t[]){') f.writeln(4*' '+'.defines = (const bench_define_t[]){')
@@ -468,6 +501,8 @@ def compile(bench_paths, **args):
% (k, k)) % (k, k))
f.writeln(4*' '+'},') f.writeln(4*' '+'},')
f.writeln(4*' '+'.define_count = %d,' % len(suite.defines)) f.writeln(4*' '+'.define_count = %d,' % len(suite.defines))
for ifdef in suite.ifdef:
f.writeln(4*' '+'#endif')
if suite.cases: if suite.cases:
f.writeln(4*' '+'.cases = (const struct bench_case[]){') f.writeln(4*' '+'.cases = (const struct bench_case[]){')
for case in suite.cases: for case in suite.cases:
@@ -479,6 +514,8 @@ def compile(bench_paths, **args):
% (' | '.join(filter(None, [ % (' | '.join(filter(None, [
'BENCH_INTERNAL' if suite.internal else None])) 'BENCH_INTERNAL' if suite.internal else None]))
or 0)) or 0))
for ifdef in it.chain(suite.ifdef, case.ifdef):
f.writeln(12*' '+'#ifdef %s' % ifdef)
# create case defines # create case defines
if case.defines: if case.defines:
f.writeln(12*' '+'.defines' f.writeln(12*' '+'.defines'
@@ -506,6 +543,8 @@ def compile(bench_paths, **args):
% (case.name)) % (case.name))
f.writeln(12*' '+'.run = __bench__%s__run,' f.writeln(12*' '+'.run = __bench__%s__run,'
% (case.name)) % (case.name))
for ifdef in it.chain(suite.ifdef, case.ifdef):
f.writeln(12*' '+'#endif')
f.writeln(8*' '+'},') f.writeln(8*' '+'},')
f.writeln(4*' '+'},') f.writeln(4*' '+'},')
f.writeln(4*' '+'.case_count = %d,' % len(suite.cases)) f.writeln(4*' '+'.case_count = %d,' % len(suite.cases))
@@ -538,6 +577,13 @@ def compile(bench_paths, **args):
# write any internal benches # write any internal benches
for suite in suites: for suite in suites:
# any ifdef prologues
if suite.ifdef:
for ifdef in suite.ifdef:
f.writeln('#ifdef %s' % ifdef)
f.writeln()
# any suite code
if suite.isin(args['source']): if suite.isin(args['source']):
if suite.code_lineno is not None: if suite.code_lineno is not None:
f.writeln('#line %d "%s"' f.writeln('#line %d "%s"'
@@ -548,10 +594,17 @@ def compile(bench_paths, **args):
% (f.lineno+1, args['output'])) % (f.lineno+1, args['output']))
f.writeln() f.writeln()
# any case functions
for case in suite.cases: for case in suite.cases:
if case.isin(args['source']): if case.isin(args['source']):
write_case_functions(f, suite, case) write_case_functions(f, suite, case)
# any ifdef epilogues
if suite.ifdef:
for ifdef in suite.ifdef:
f.writeln('#endif')
f.writeln()
# declare our bench suites # declare our bench suites
# #
# by declaring these as weak we can write these to every # by declaring these as weak we can write these to every
@@ -1486,7 +1539,7 @@ if __name__ == "__main__":
bench_parser.add_argument( bench_parser.add_argument(
'-a', '--all', '-a', '--all',
action='store_true', action='store_true',
help="Ignore test filters.") help="Ignore bench filters.")
bench_parser.add_argument( bench_parser.add_argument(
'-d', '--disk', '-d', '--disk',
help="Direct block device operations to this file.") help="Direct block device operations to this file.")

View File

@@ -55,6 +55,9 @@ class TestCase:
self.if_ = config.pop('if', []) self.if_ = config.pop('if', [])
if not isinstance(self.if_, list): if not isinstance(self.if_, list):
self.if_ = [self.if_] self.if_ = [self.if_]
self.ifdef = config.pop('ifdef', [])
if not isinstance(self.ifdef, list):
self.ifdef = [self.ifdef]
self.code = config.pop('code') self.code = config.pop('code')
self.code_lineno = config.pop('code_lineno', None) self.code_lineno = config.pop('code_lineno', None)
self.in_ = config.pop('in', self.in_ = config.pop('in',
@@ -204,6 +207,10 @@ class TestSuite:
if not isinstance(self.if_, list): if not isinstance(self.if_, list):
self.if_ = [self.if_] self.if_ = [self.if_]
self.ifdef = config.pop('ifdef', [])
if not isinstance(self.ifdef, list):
self.ifdef = [self.ifdef]
self.code = config.pop('code', None) self.code = config.pop('code', None)
self.code_lineno = min( self.code_lineno = min(
(l for l in code_linenos (l for l in code_linenos
@@ -368,6 +375,12 @@ def compile(test_paths, **args):
# note it's up to the specific generated file to declare # note it's up to the specific generated file to declare
# the test defines # the test defines
def write_case_functions(f, suite, case): def write_case_functions(f, suite, case):
# write any ifdef prologues
if case.ifdef:
for ifdef in case.ifdef:
f.writeln('#ifdef %s' % ifdef)
f.writeln()
# create case define functions # create case define functions
for i, permutation in enumerate(case.permutations): for i, permutation in enumerate(case.permutations):
for k, vs in sorted(permutation.items()): for k, vs in sorted(permutation.items()):
@@ -424,7 +437,19 @@ def compile(test_paths, **args):
f.writeln('}') f.writeln('}')
f.writeln() f.writeln()
# write any ifdef epilogues
if case.ifdef:
for ifdef in case.ifdef:
f.writeln('#endif')
f.writeln()
if not args.get('source'): if not args.get('source'):
# write any ifdef prologues
if suite.ifdef:
for ifdef in suite.ifdef:
f.writeln('#ifdef %s' % ifdef)
f.writeln()
# write any suite defines # write any suite defines
if suite.defines: if suite.defines:
for define in sorted(suite.defines): for define in sorted(suite.defines):
@@ -462,6 +487,12 @@ def compile(test_paths, **args):
% (case.name)) % (case.name))
f.writeln() f.writeln()
# write any ifdef epilogues
if suite.ifdef:
for ifdef in suite.ifdef:
f.writeln('#endif')
f.writeln()
# create suite struct # create suite struct
f.writeln('const struct test_suite __test__%s__suite = {' f.writeln('const struct test_suite __test__%s__suite = {'
% suite.name) % suite.name)
@@ -473,6 +504,8 @@ def compile(test_paths, **args):
'TEST_REENTRANT' if suite.reentrant else None, 'TEST_REENTRANT' if suite.reentrant else None,
'TEST_FUZZ' if suite.fuzz else None])) 'TEST_FUZZ' if suite.fuzz else None]))
or 0)) or 0))
for ifdef in suite.ifdef:
f.writeln(4*' '+'#ifdef %s' % ifdef)
# create suite defines # create suite defines
if suite.defines: if suite.defines:
f.writeln(4*' '+'.defines = (const test_define_t[]){') f.writeln(4*' '+'.defines = (const test_define_t[]){')
@@ -481,6 +514,8 @@ def compile(test_paths, **args):
% (k, k)) % (k, k))
f.writeln(4*' '+'},') f.writeln(4*' '+'},')
f.writeln(4*' '+'.define_count = %d,' % len(suite.defines)) f.writeln(4*' '+'.define_count = %d,' % len(suite.defines))
for ifdef in suite.ifdef:
f.writeln(4*' '+'#endif')
if suite.cases: if suite.cases:
f.writeln(4*' '+'.cases = (const struct test_case[]){') f.writeln(4*' '+'.cases = (const struct test_case[]){')
for case in suite.cases: for case in suite.cases:
@@ -494,6 +529,8 @@ def compile(test_paths, **args):
'TEST_REENTRANT' if case.reentrant else None, 'TEST_REENTRANT' if case.reentrant else None,
'TEST_FUZZ' if case.fuzz else None])) 'TEST_FUZZ' if case.fuzz else None]))
or 0)) or 0))
for ifdef in it.chain(suite.ifdef, case.ifdef):
f.writeln(12*' '+'#ifdef %s' % ifdef)
# create case defines # create case defines
if case.defines: if case.defines:
f.writeln(12*' '+'.defines' f.writeln(12*' '+'.defines'
@@ -521,6 +558,8 @@ def compile(test_paths, **args):
% (case.name)) % (case.name))
f.writeln(12*' '+'.run = __test__%s__run,' f.writeln(12*' '+'.run = __test__%s__run,'
% (case.name)) % (case.name))
for ifdef in it.chain(suite.ifdef, case.ifdef):
f.writeln(12*' '+'#endif')
f.writeln(8*' '+'},') f.writeln(8*' '+'},')
f.writeln(4*' '+'},') f.writeln(4*' '+'},')
f.writeln(4*' '+'.case_count = %d,' % len(suite.cases)) f.writeln(4*' '+'.case_count = %d,' % len(suite.cases))
@@ -553,6 +592,13 @@ def compile(test_paths, **args):
# write any internal tests # write any internal tests
for suite in suites: for suite in suites:
# any ifdef prologues
if suite.ifdef:
for ifdef in suite.ifdef:
f.writeln('#ifdef %s' % ifdef)
f.writeln()
# any suite code
if suite.isin(args['source']): if suite.isin(args['source']):
if suite.code_lineno is not None: if suite.code_lineno is not None:
f.writeln('#line %d "%s"' f.writeln('#line %d "%s"'
@@ -563,10 +609,17 @@ def compile(test_paths, **args):
% (f.lineno+1, args['output'])) % (f.lineno+1, args['output']))
f.writeln() f.writeln()
# any case functions
for case in suite.cases: for case in suite.cases:
if case.isin(args['source']): if case.isin(args['source']):
write_case_functions(f, suite, case) write_case_functions(f, suite, case)
# any ifdef epilogues
if suite.ifdef:
for ifdef in suite.ifdef:
f.writeln('#endif')
f.writeln()
# declare our test suites # declare our test suites
# #
# by declaring these as weak we can write these to every # by declaring these as weak we can write these to every

View File

@@ -2,6 +2,7 @@
after = ['test_traversal', 'test_gc', 'test_mount'] after = ['test_traversal', 'test_gc', 'test_mount']
# Test filesystem-level checksum things # Test filesystem-level checksum things
# test we can detect at least fully clobbered blocks # test we can detect at least fully clobbered blocks
@@ -804,6 +805,7 @@ defines.BADBLOCK_BEHAVIOR = [
] ]
# this should stay inlined # this should stay inlined
defines.SIZE = 'BLOCK_SIZE/16' defines.SIZE = 'BLOCK_SIZE/16'
ifdef = 'LFS_CKREADS'
code = ''' code = '''
// test all bad bits in the mroot // test all bad bits in the mroot
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
@@ -915,6 +917,7 @@ defines.BADBLOCK_BEHAVIOR = [
] ]
# this should create a single block file # this should create a single block file
defines.SIZE = 'BLOCK_SIZE' defines.SIZE = 'BLOCK_SIZE'
ifdef = 'LFS_CKREADS'
code = ''' code = '''
// first we need to figure out where the data block will actually // first we need to figure out where the data block will actually
// end up, fortunately our block randomization is intentionally // end up, fortunately our block randomization is intentionally
@@ -1048,6 +1051,7 @@ defines.INLINE_SIZE = 0
defines.CRYSTAL_THRESH = -1 defines.CRYSTAL_THRESH = -1
defines.FRAGMENT_SIZE = 'BLOCK_SIZE/8' defines.FRAGMENT_SIZE = 'BLOCK_SIZE/8'
defines.SIZE = '2*FRAGMENT_SIZE' defines.SIZE = '2*FRAGMENT_SIZE'
ifdef = 'LFS_CKREADS'
code = ''' code = '''
// first we need to figure out where the btree block will actually // first we need to figure out where the btree block will actually
// end up, fortunately our block randomization is intentionally // end up, fortunately our block randomization is intentionally

View File

@@ -18,13 +18,14 @@ defines.CKPROGS = [false, true]
defines.CKREADS = [false, true] defines.CKREADS = [false, true]
defines.FLUSH = [false, true] defines.FLUSH = [false, true]
defines.SYNC = [false, true] defines.SYNC = [false, true]
if = 'LFS_IFDEF_CKREADS(true, !CKREADS)'
code = ''' code = '''
lfs_t lfs; lfs_t lfs;
lfsr_format(&lfs, CFG) => 0; lfsr_format(&lfs, CFG) => 0;
lfsr_mount(&lfs, lfsr_mount(&lfs,
((RDONLY) ? LFS_M_RDONLY : LFS_M_RDWR) ((RDONLY) ? LFS_M_RDONLY : LFS_M_RDWR)
| ((CKPROGS) ? LFS_M_CKPROGS : 0) | ((CKPROGS) ? LFS_M_CKPROGS : 0)
| ((CKREADS) ? LFS_M_CKREADS : 0) | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_M_CKREADS, 0) : 0)
| ((FLUSH) ? LFS_M_FLUSH : 0) | ((FLUSH) ? LFS_M_FLUSH : 0)
| ((SYNC) ? LFS_M_SYNC : 0), | ((SYNC) ? LFS_M_SYNC : 0),
CFG) => 0; CFG) => 0;
@@ -34,7 +35,7 @@ code = '''
assert(fsinfo.flags == ( assert(fsinfo.flags == (
((RDONLY) ? LFS_I_RDONLY : 0) ((RDONLY) ? LFS_I_RDONLY : 0)
| ((CKPROGS) ? LFS_I_CKPROGS : 0) | ((CKPROGS) ? LFS_I_CKPROGS : 0)
| ((CKREADS) ? LFS_I_CKREADS : 0) | ((CKREADS) ? LFS_IFDEF_CKREADS(LFS_I_CKREADS, 0) : 0)
| ((FLUSH) ? LFS_I_FLUSH : 0) | ((FLUSH) ? LFS_I_FLUSH : 0)
| ((SYNC) ? LFS_I_SYNC : 0) | ((SYNC) ? LFS_I_SYNC : 0)
| LFS_I_CANLOOKAHEAD | LFS_I_CANLOOKAHEAD