Tweaked lfsr_file_open to sync when LFS_O_SYNC
So now the following creates a reg file (instead of just a stickynote):
lfsr_file_open(&lfs, &file, "test.txt",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL | LFS_O_SYNC) => 0;
// powerloss!!
struct lfsr_info info;
lfsr_stat(&lfs, "test.txt", &info) => 0; // LFS_ERR_NOENT before
assert(info.type == LFS_TYPE_REG);
This hopefully results in more intuitive behavior around lfsr_file_open
with LFS_O_SYNC. Which is important as LFS_O_SYNC is often used as an
escape hatch to avoid needing to reason about syncing things when
performance is not a big concern.
Unfortunately this does come with a surprisingly big code/stack cost,
but I'm thinking of putting these flags (LFS_O_FLUSH/LFS_O_SYNC) behind
ifdefs anyways (LFS_MAYBE_SYNC?):
code stack ctx
before: 35780 2440 640
after: 35836 (+0.2%) 2488 (+2.0%) 640 (+0.0%)
Also added some more tests to make sure these open+LFS_O_SYNC cases are
explicitly covered:
- test_fsync_sync_o_wrr
- test_fsync_sync_o_wwrr
- test_fsync_desync_o_wdwrr
- test_fsync_resync_o_wdwyrr
This does make a bit of a mess when you combined LFS_O_SYNC +
LFS_O_DESYNC. What exactly should a SYNC + DESYNC file look like?
For now I've just made LFS_O_SYNC + LFS_O_DESYNC behave as if you opened
a file with LFS_O_SYNC and then immediately called lfsr_file_desync on
it. So it doesn't receive broadcasts, but _does_ create the reg file,
and _does_ sync on first write, clearing the desync flag.
But this may be worth revisiting. Maybe LFS_O_DESYNC files shouldn't
have their desync flags cleared unless lfsr_file_sync is explicitly
called? Or maybe LFS_O_SYNC + LFS_O_DESYNC should just be an error?
Unsure...
This commit is contained in:
@@ -11339,6 +11339,9 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
|
||||
|| !lfsr_o_isexcl(cfg->attrs[i].flags));
|
||||
}
|
||||
|
||||
// mounted with LFS_M_FLUSH/SYNC? implies LFS_O_FLUSH/SYNC
|
||||
flags |= lfs->flags & (LFS_M_FLUSH | LFS_M_SYNC);
|
||||
|
||||
if (!lfsr_o_isrdonly(flags)) {
|
||||
// prepare our filesystem for writing
|
||||
int err = lfsr_fs_mkconsistent(lfs);
|
||||
@@ -11350,8 +11353,6 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
|
||||
// setup file state
|
||||
file->cfg = cfg;
|
||||
file->b.o.flags = lfsr_o_settype(flags, LFS_TYPE_REG)
|
||||
// mounted with LFS_M_FLUSH/SYNC? implies LFS_O_FLUSH/SYNC
|
||||
| (lfs->flags & (LFS_M_FLUSH | LFS_M_SYNC))
|
||||
// default to unflushed for orphans/truncated files
|
||||
| LFS_o_UNFLUSH;
|
||||
file->pos = 0;
|
||||
@@ -11441,8 +11442,7 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
|
||||
file->cache.size = 0;
|
||||
|
||||
// fetch the file struct and custom attrs
|
||||
err = lfsr_file_fetch(lfs, file,
|
||||
lfsr_o_istrunc(file->b.o.flags));
|
||||
err = lfsr_file_fetch(lfs, file, lfsr_o_istrunc(flags));
|
||||
if (err) {
|
||||
goto failed;
|
||||
}
|
||||
@@ -11457,6 +11457,23 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
|
||||
|
||||
// add to tracked mdirs
|
||||
lfsr_omdir_open(lfs, &file->b.o);
|
||||
|
||||
// sync if requested
|
||||
if (lfsr_o_issync(flags) && !lfsr_o_isrdonly(flags)) {
|
||||
err = lfsr_file_sync(lfs, file);
|
||||
if (err) {
|
||||
lfsr_omdir_close(lfs, &file->b.o);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
// TODO should we do this for all LFS_O_SYNC operations?
|
||||
// sync clears the desync flag, so reset it if we're desync
|
||||
//
|
||||
// note this matches the behavior of calling lfsr_file_sync and
|
||||
// then lfsr_file_desync after opening the file
|
||||
file->b.o.flags |= flags & LFS_O_DESYNC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:;
|
||||
|
||||
@@ -104,6 +104,98 @@ code = '''
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# test that LFS_O_SYNC/LFS_O_FLUSH flags work as expected
|
||||
[cases.test_fsync_sync_o_wrr]
|
||||
# SYNC=0 => no sync, readers not updated
|
||||
# SYNC=1 => sync via lfsr_file_sync
|
||||
# SYNC=2 => sync via LFS_O_SYNC
|
||||
# SYNC=3 => sync via LFS_M_SYNC
|
||||
defines.SYNC = [2, 3]
|
||||
# FLUSH=0 => no flush
|
||||
# FLUSH=1 => flush via lfsr_file_flush
|
||||
# FLUSH=2 => flush via LFS_O_FLUSH
|
||||
# FLUSH=3 => flush via LFS_M_FLUSH
|
||||
defines.FLUSH = [0, 2, 3]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||
lfsr_mount(&lfs,
|
||||
LFS_M_RDWR
|
||||
| ((FLUSH == 3) ? LFS_M_FLUSH : 0)
|
||||
| ((SYNC == 3) ? LFS_M_SYNC : 0),
|
||||
CFG) => 0;
|
||||
|
||||
// a - writer
|
||||
// b - reader kept open, recvs updates from a
|
||||
// c - reader kept closed, checks disk state
|
||||
lfsr_file_t a;
|
||||
lfsr_file_t b;
|
||||
lfsr_file_t c;
|
||||
uint8_t rbuf[256];
|
||||
// LFS_O_SYNC/LFS_M_SYNC should immediately create the file
|
||||
lfsr_file_open(&lfs, &a, "jello",
|
||||
LFS_O_WRONLY
|
||||
| LFS_O_CREAT
|
||||
| LFS_O_EXCL
|
||||
| ((FLUSH == 2) ? LFS_O_FLUSH : 0)
|
||||
| ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
struct lfs_info info;
|
||||
lfsr_stat(&lfs, "jello", &info) => 0;
|
||||
assert(strcmp(info.name, "jello") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(info.size == 0);
|
||||
// create the other files
|
||||
lfsr_file_open(&lfs, &b, "jello", LFS_O_RDONLY) => 0;
|
||||
|
||||
// write to a
|
||||
lfsr_file_write(&lfs, &a, "hello!", strlen("hello!"))
|
||||
=> strlen("hello!");
|
||||
|
||||
// should immediately show up in b
|
||||
lfsr_file_read(&lfs, &b, rbuf, sizeof(rbuf)) => strlen("hello!");
|
||||
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &c, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("hello!");
|
||||
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
||||
lfsr_file_close(&lfs, &c) => 0;
|
||||
|
||||
// lets rewrite a
|
||||
lfsr_file_rewind(&lfs, &a) => 0;
|
||||
lfsr_file_write(&lfs, &a, "bonjour!", strlen("bonjour!"))
|
||||
=> strlen("bonjour!");
|
||||
|
||||
// should immediately show up in b
|
||||
lfsr_file_rewind(&lfs, &b) => 0;
|
||||
lfsr_file_read(&lfs, &b, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &c, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
lfsr_file_close(&lfs, &c) => 0;
|
||||
|
||||
// lets rewrite a one last time
|
||||
lfsr_file_rewind(&lfs, &a) => 0;
|
||||
lfsr_file_write(&lfs, &a, "ohayo!", strlen("ohayo!"))
|
||||
=> strlen("ohayo!");
|
||||
// close a
|
||||
lfsr_file_close(&lfs, &a) => 0;
|
||||
|
||||
// should immediately show up in b
|
||||
lfsr_file_rewind(&lfs, &b) => 0;
|
||||
lfsr_file_read(&lfs, &b, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &c, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
lfsr_file_close(&lfs, &c) => 0;
|
||||
|
||||
lfsr_file_close(&lfs, &b) => 0;
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[cases.test_fsync_sync_wwrr]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
@@ -224,6 +316,128 @@ code = '''
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# test that LFS_O_SYNC/LFS_O_FLUSH flags work as expected
|
||||
[cases.test_fsync_sync_o_wwrr]
|
||||
# SYNC=0 => no sync, readers not updated
|
||||
# SYNC=1 => sync via lfsr_file_sync
|
||||
# SYNC=2 => sync via LFS_O_SYNC
|
||||
# SYNC=3 => sync via LFS_M_SYNC
|
||||
defines.SYNC = [2, 3]
|
||||
# FLUSH=0 => no flush
|
||||
# FLUSH=1 => flush via lfsr_file_flush
|
||||
# FLUSH=2 => flush via LFS_O_FLUSH
|
||||
# FLUSH=3 => flush via LFS_M_FLUSH
|
||||
defines.FLUSH = [0, 2, 3]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||
lfsr_mount(&lfs,
|
||||
LFS_M_RDWR
|
||||
| ((FLUSH == 3) ? LFS_M_FLUSH : 0)
|
||||
| ((SYNC == 3) ? LFS_M_SYNC : 0),
|
||||
CFG) => 0;
|
||||
|
||||
// a - writer
|
||||
// b - writer
|
||||
// c - reader kept open, recvs updates from a/b
|
||||
// d - reader kept closed, checks disk state
|
||||
lfsr_file_t a;
|
||||
lfsr_file_t b;
|
||||
lfsr_file_t c;
|
||||
lfsr_file_t d;
|
||||
uint8_t rbuf[256];
|
||||
// LFS_O_SYNC/LFS_M_SYNC should immediately create the file
|
||||
lfsr_file_open(&lfs, &a, "jello",
|
||||
LFS_O_WRONLY
|
||||
| LFS_O_CREAT
|
||||
| LFS_O_EXCL
|
||||
| ((FLUSH == 2) ? LFS_O_FLUSH : 0)
|
||||
| ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
struct lfs_info info;
|
||||
lfsr_stat(&lfs, "jello", &info) => 0;
|
||||
assert(strcmp(info.name, "jello") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(info.size == 0);
|
||||
// create the other files
|
||||
lfsr_file_open(&lfs, &b, "jello",
|
||||
LFS_O_WRONLY
|
||||
| ((FLUSH == 2) ? LFS_O_FLUSH : 0)
|
||||
| ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
lfsr_file_open(&lfs, &c, "jello", LFS_O_RDONLY) => 0;
|
||||
|
||||
// write to a
|
||||
lfsr_file_write(&lfs, &a, "hello!", strlen("hello!"))
|
||||
=> strlen("hello!");
|
||||
|
||||
// should immediately show up in c
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("hello!");
|
||||
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("hello!");
|
||||
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// write to b
|
||||
lfsr_file_write(&lfs, &b, "bonjour!", strlen("bonjour!"))
|
||||
=> strlen("bonjour!");
|
||||
|
||||
// should immediately show up in c
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// sync a
|
||||
lfsr_file_sync(&lfs, &a) => 0;
|
||||
|
||||
// a's contents were clobbered, so we should see b
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// lets rewrite a one last time
|
||||
lfsr_file_rewind(&lfs, &a) => 0;
|
||||
lfsr_file_write(&lfs, &a, "ohayo!", strlen("ohayo!"))
|
||||
=> strlen("ohayo!");
|
||||
|
||||
// should immediately show up in c
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// close a and b
|
||||
lfsr_file_close(&lfs, &a) => 0;
|
||||
lfsr_file_close(&lfs, &b) => 0;
|
||||
|
||||
// should still have a
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
lfsr_file_close(&lfs, &c) => 0;
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[cases.test_fsync_sync_wwrr_zero]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
@@ -2183,6 +2397,199 @@ code = '''
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# test that LFS_O_SYNC/LFS_O_FLUSH flags work as expected
|
||||
[cases.test_fsync_desync_o_wdwrr]
|
||||
# SYNC=0 => no sync, readers not updated
|
||||
# SYNC=1 => sync via lfsr_file_sync
|
||||
# SYNC=2 => sync via LFS_O_SYNC
|
||||
# SYNC=3 => sync via LFS_M_SYNC
|
||||
defines.SYNC = [2, 3]
|
||||
# FLUSH=0 => no flush
|
||||
# FLUSH=1 => flush via lfsr_file_flush
|
||||
# FLUSH=2 => flush via LFS_O_FLUSH
|
||||
# FLUSH=3 => flush via LFS_M_FLUSH
|
||||
defines.FLUSH = [0, 2, 3]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||
lfsr_mount(&lfs,
|
||||
LFS_M_RDWR
|
||||
| ((FLUSH == 3) ? LFS_M_FLUSH : 0)
|
||||
| ((SYNC == 3) ? LFS_M_SYNC : 0),
|
||||
CFG) => 0;
|
||||
|
||||
// a - desynced writer
|
||||
// b - writer
|
||||
// c - reader kept open, recvs updates from a
|
||||
// d - reader kept closed, checks disk state
|
||||
lfsr_file_t a;
|
||||
lfsr_file_t b;
|
||||
lfsr_file_t c;
|
||||
lfsr_file_t d;
|
||||
uint8_t rbuf[256];
|
||||
// LFS_O_SYNC/LFS_M_SYNC should immediately create the file
|
||||
lfsr_file_open(&lfs, &a, "jello",
|
||||
LFS_O_WRONLY
|
||||
| LFS_O_CREAT
|
||||
| LFS_O_EXCL
|
||||
| ((FLUSH == 2) ? LFS_O_FLUSH : 0)
|
||||
| ((SYNC == 2) ? LFS_O_SYNC : 0)
|
||||
| LFS_O_DESYNC) => 0;
|
||||
struct lfs_info info;
|
||||
lfsr_stat(&lfs, "jello", &info) => 0;
|
||||
assert(strcmp(info.name, "jello") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(info.size == 0);
|
||||
// create the other files
|
||||
lfsr_file_open(&lfs, &b, "jello",
|
||||
LFS_O_WRONLY
|
||||
| ((FLUSH == 2) ? LFS_O_FLUSH : 0)
|
||||
| ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
lfsr_file_open(&lfs, &c, "jello", LFS_O_RDONLY) => 0;
|
||||
|
||||
// write to b
|
||||
lfsr_file_write(&lfs, &b, "hello!", strlen("hello!"))
|
||||
=> strlen("hello!");
|
||||
|
||||
// our write should show up in c
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("hello!");
|
||||
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("hello!");
|
||||
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// sync a
|
||||
lfsr_file_sync(&lfs, &a) => 0;
|
||||
|
||||
// c should revert to a's contents
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => 0;
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => 0;
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// rewrite a
|
||||
lfsr_file_write(&lfs, &a, "bonjour!", strlen("bonjour!"))
|
||||
=> strlen("bonjour!");
|
||||
|
||||
// should immediately show up in c
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// sync b
|
||||
lfsr_file_sync(&lfs, &b) => 0;
|
||||
|
||||
// should still have a
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// rewrite b
|
||||
lfsr_file_rewind(&lfs, &b) => 0;
|
||||
lfsr_file_write(&lfs, &b, "ohayo!", strlen("ohayo!"))
|
||||
=> strlen("ohayo!");
|
||||
|
||||
// should immediately show up in c
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// sync a
|
||||
lfsr_file_sync(&lfs, &a) => 0;
|
||||
|
||||
// c should still have b, this may be surprising, but the implicit
|
||||
// sync when we rewrote a clears the desync flag
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// desync a
|
||||
lfsr_file_desync(&lfs, &a) => 0;
|
||||
// rewrite b
|
||||
lfsr_file_rewind(&lfs, &b) => 0;
|
||||
lfsr_file_write(&lfs, &b, "zdrasti!", strlen("zdrasti!"))
|
||||
=> strlen("zdrasti!");
|
||||
|
||||
// should immediately show up in c
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("zdrasti!");
|
||||
assert(memcmp(rbuf, "zdrasti!", strlen("zdrasti!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("zdrasti!");
|
||||
assert(memcmp(rbuf, "zdrasti!", strlen("zdrasti!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// sync a
|
||||
lfsr_file_sync(&lfs, &a) => 0;
|
||||
|
||||
// c should revert to a's contents
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// lets rewrite a one last time
|
||||
lfsr_file_rewind(&lfs, &a) => 0;
|
||||
lfsr_file_write(&lfs, &a, "annyeong!", strlen("annyeong!"))
|
||||
=> strlen("annyeong!");
|
||||
|
||||
// should immediately show up in c
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("annyeong!");
|
||||
assert(memcmp(rbuf, "annyeong!", strlen("annyeong!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("annyeong!");
|
||||
assert(memcmp(rbuf, "annyeong!", strlen("annyeong!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// close a and b
|
||||
lfsr_file_close(&lfs, &a) => 0;
|
||||
lfsr_file_close(&lfs, &b) => 0;
|
||||
|
||||
// should still have a
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("annyeong!");
|
||||
assert(memcmp(rbuf, "annyeong!", strlen("annyeong!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("annyeong!");
|
||||
assert(memcmp(rbuf, "annyeong!", strlen("annyeong!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
lfsr_file_close(&lfs, &c) => 0;
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[cases.test_fsync_desync_wwdrr_zero]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
@@ -3807,6 +4214,189 @@ code = '''
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
# test that LFS_O_SYNC/LFS_O_FLUSH flags work as expected
|
||||
[cases.test_fsync_resync_o_wdwyrr]
|
||||
# SYNC=0 => no sync, readers not updated
|
||||
# SYNC=1 => sync via lfsr_file_sync
|
||||
# SYNC=2 => sync via LFS_O_SYNC
|
||||
# SYNC=3 => sync via LFS_M_SYNC
|
||||
defines.SYNC = [2, 3]
|
||||
# FLUSH=0 => no flush
|
||||
# FLUSH=1 => flush via lfsr_file_flush
|
||||
# FLUSH=2 => flush via LFS_O_FLUSH
|
||||
# FLUSH=3 => flush via LFS_M_FLUSH
|
||||
defines.FLUSH = [0, 2, 3]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||
lfsr_mount(&lfs,
|
||||
LFS_M_RDWR
|
||||
| ((FLUSH == 3) ? LFS_M_FLUSH : 0)
|
||||
| ((SYNC == 3) ? LFS_M_SYNC : 0),
|
||||
CFG) => 0;
|
||||
|
||||
// a - desynced writer
|
||||
// b - writer
|
||||
// c - reader kept open, recvs updates from a
|
||||
// d - reader kept closed, checks disk state
|
||||
lfsr_file_t a;
|
||||
lfsr_file_t b;
|
||||
lfsr_file_t c;
|
||||
lfsr_file_t d;
|
||||
uint8_t rbuf[256];
|
||||
// LFS_O_SYNC/LFS_M_SYNC should immediately create the file
|
||||
lfsr_file_open(&lfs, &a, "jello",
|
||||
LFS_O_WRONLY
|
||||
| LFS_O_CREAT
|
||||
| LFS_O_EXCL
|
||||
| ((FLUSH == 2) ? LFS_O_FLUSH : 0)
|
||||
| ((SYNC == 2) ? LFS_O_SYNC : 0)
|
||||
| LFS_O_DESYNC) => 0;
|
||||
struct lfs_info info;
|
||||
lfsr_stat(&lfs, "jello", &info) => 0;
|
||||
assert(strcmp(info.name, "jello") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(info.size == 0);
|
||||
// create the other files
|
||||
lfsr_file_open(&lfs, &b, "jello",
|
||||
LFS_O_WRONLY
|
||||
| ((FLUSH == 2) ? LFS_O_FLUSH : 0)
|
||||
| ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
lfsr_file_open(&lfs, &c, "jello", LFS_O_RDONLY) => 0;
|
||||
|
||||
// write to b
|
||||
lfsr_file_write(&lfs, &b, "hello!", strlen("hello!"))
|
||||
=> strlen("hello!");
|
||||
|
||||
// our write should show up in c
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("hello!");
|
||||
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("hello!");
|
||||
assert(memcmp(rbuf, "hello!", strlen("hello!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// sync a
|
||||
lfsr_file_sync(&lfs, &a) => 0;
|
||||
|
||||
// c should revert to a's contents
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => 0;
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => 0;
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// reopen a
|
||||
lfsr_file_close(&lfs, &a) => 0;
|
||||
lfsr_file_open(&lfs, &a, "jello",
|
||||
LFS_O_WRONLY
|
||||
| ((FLUSH == 2) ? LFS_O_FLUSH : 0)
|
||||
| ((SYNC == 2) ? LFS_O_SYNC : 0)
|
||||
| LFS_O_DESYNC) => 0;
|
||||
// rewrite b
|
||||
lfsr_file_rewind(&lfs, &b) => 0;
|
||||
lfsr_file_write(&lfs, &b, "bonjour!", strlen("bonjour!"))
|
||||
=> strlen("bonjour!");
|
||||
|
||||
// should immediately show up in c
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// resync a
|
||||
lfsr_file_resync(&lfs, &a) => 0;
|
||||
// sync a
|
||||
lfsr_file_sync(&lfs, &a) => 0;
|
||||
|
||||
// c should still show b
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// desync a
|
||||
lfsr_file_desync(&lfs, &a) => 0;
|
||||
// rewrite b
|
||||
lfsr_file_rewind(&lfs, &b) => 0;
|
||||
lfsr_file_write(&lfs, &b, "ohayo!r!", strlen("ohayo!r!"))
|
||||
=> strlen("ohayo!r!");
|
||||
|
||||
// should immediately show up in c
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("ohayo!r!");
|
||||
assert(memcmp(rbuf, "ohayo!r!", strlen("ohayo!r!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// sync a
|
||||
lfsr_file_sync(&lfs, &a) => 0;
|
||||
|
||||
// c should revert to a's contents
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("bonjour!");
|
||||
assert(memcmp(rbuf, "bonjour!", strlen("bonjour!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// rewrite a
|
||||
lfsr_file_rewind(&lfs, &a) => 0;
|
||||
lfsr_file_write(&lfs, &a, "annyeong!", strlen("annyeong!"))
|
||||
=> strlen("annyeong!");
|
||||
// desync b
|
||||
lfsr_file_desync(&lfs, &b) => 0;
|
||||
// resync b
|
||||
lfsr_file_resync(&lfs, &b) => 0;
|
||||
// rewrite b
|
||||
lfsr_file_rewind(&lfs, &b) => 0;
|
||||
lfsr_file_write(&lfs, &b, "zdrasti!", strlen("zdrasti!"))
|
||||
=> strlen("zdrasti!");
|
||||
|
||||
// should immediately show up in c
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("zdrasti!!");
|
||||
assert(memcmp(rbuf, "zdrasti!!", strlen("zdrasti!!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("zdrasti!!");
|
||||
assert(memcmp(rbuf, "zdrasti!!", strlen("zdrasti!!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
// close b
|
||||
lfsr_file_close(&lfs, &b) => 0;
|
||||
// close a
|
||||
lfsr_file_close(&lfs, &a) => 0;
|
||||
|
||||
// c should still show b's changes
|
||||
lfsr_file_rewind(&lfs, &c) => 0;
|
||||
lfsr_file_read(&lfs, &c, rbuf, sizeof(rbuf)) => strlen("zdrasti!!");
|
||||
assert(memcmp(rbuf, "zdrasti!!", strlen("zdrasti!!")) == 0);
|
||||
// and on disk
|
||||
lfsr_file_open(&lfs, &d, "jello", LFS_O_RDONLY) => 0;
|
||||
lfsr_file_read(&lfs, &d, rbuf, sizeof(rbuf)) => strlen("zdrasti!!");
|
||||
assert(memcmp(rbuf, "zdrasti!!", strlen("zdrasti!!")) == 0);
|
||||
lfsr_file_close(&lfs, &d) => 0;
|
||||
|
||||
lfsr_file_close(&lfs, &c) => 0;
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[cases.test_fsync_resync_wwdyrr_zero]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
|
||||
Reference in New Issue
Block a user