Reworked stickynote API, exposed LFS_TYPE_STICKYNOTE to users

This adds the LFS_TYPE_STICKYNOTE type, allowing users to interact with
stickynotes as long as they aren't orphaned.

This hopefully solves the long-standing mess that was the LFS_O_EXCL
API.

---

As for what I mean by orphaned vs non-orphaned stickynotes:

Non-orphaned stickynotes represent files that have been "created" (via
LFS_O_CREAT), but not "committed" (via sync/close). You can still close
and convert the stickynote to a reg file, so these aren't orphans. These
are also called "uncreated" files in some parts of the codebase:

- open+O_CREAT -> non-orphaned stickynote (uncreated file)

Orphaned stickynotes are possible by either removing an open file, or
desyncing a file before sync/close. These are still invisible to the
user and will be eventually cleaned up after the last file handle is
closed:

- open+remove               -> orphaned stickynote (zombied file)
- open+O_CREAT+desync+close -> orphaned stickynote (orphaned file)

Desynced files are a bit special. Even though they technically aren't
orphaned, they also behave like orphaned file handles:

- open+O_CREAT+close -> orphaned stickynote (desynced file)

The idea is this mimics the state of files post-close, and allows for
some tricks like using a desync file as a temporary file with no
observable effects on the filesystem.

---

The motivation for this comes from staring at the LFS_O_EXCL API for too
long and realizing the problem is that littlefs's API contradicts itself
when it comes to whether or not uncreated files exist.

This solution is to consistently treat uncreated files as though they
exist (the alternative would make LFS_O_EXCL pretty much useless), but I
really didn't want to do this as having what appears to be normal files
disappear after powerloss risks confusion.

The compromise here is to give these files a special type, repurposing
the internal LFS_TAG_STICKYNOTE, which hopefully hints to the user these
won't behave like normal files.

If the user is more interested in POSIX compatibility, they can always
map these to either LFS_TYPE_REG or LFS_ERR_NOENT, whichever they think
is the least confusing.

As a quirk of littlefs's API, stickynotes should never actually contain
any data, and will always have size 0.

However they can have custom attributes assigned now (which is I guess
ok? also TODO should probably test this).

---

The implementation right now is a bit naive, I mostly just wanted to get
the tests working again in this new model. It may be possible to claw
back some of this code cost:

           code          stack          ctx
  before: 35740           2440          640
  after:  35952 (+0.6%)   2440 (+0.0%)  640 (+0.0%)
This commit is contained in:
Christopher Haster
2025-04-22 15:24:42 -05:00
parent 0a485da7c9
commit 76493142e7
10 changed files with 6177 additions and 1693 deletions
+81 -48
View File
@@ -9311,9 +9311,11 @@ static int lfsr_mtree_pathlookup(lfs_t *lfs, const char **path,
// only continue if we hit a directory // only continue if we hit a directory
if (tag != LFSR_TAG_DIR) { if (tag != LFSR_TAG_DIR) {
return (tag == LFSR_TAG_STICKYNOTE) return (tag == LFSR_TAG_STICKYNOTE
&& !lfsr_omdir_ismidopen(lfs, mdir.mid,
~(LFS_o_ZOMBIE | LFS_O_DESYNC)))
? LFS_ERR_NOENT ? LFS_ERR_NOENT
: (tag == LFSR_TAG_REG) : (tag == LFSR_TAG_REG || tag == LFSR_TAG_STICKYNOTE)
? LFS_ERR_NOTDIR ? LFS_ERR_NOTDIR
: LFS_ERR_NOTSUP; : LFS_ERR_NOTSUP;
} }
@@ -10176,9 +10178,14 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
if (err && !(err == LFS_ERR_NOENT && lfsr_path_islast(path))) { if (err && !(err == LFS_ERR_NOENT && lfsr_path_islast(path))) {
return err; return err;
} }
// already exists? stickynotes don't really exist // TODO LFSR_TAG_ORPHAN maybe?
// already exists? if we find a stickynote, check to see if there
// are any open in-sync file handles to decide if it really exists
bool exists = (err != LFS_ERR_NOENT); bool exists = (err != LFS_ERR_NOENT);
if (exists && tag != LFSR_TAG_STICKYNOTE) { if (exists
&& (tag != LFSR_TAG_STICKYNOTE
|| lfsr_omdir_ismidopen(lfs, mdir.mid,
~(LFS_o_ZOMBIE | LFS_O_DESYNC)))) {
return LFS_ERR_EXIST; return LFS_ERR_EXIST;
} }
@@ -10403,12 +10410,17 @@ int lfsr_remove(lfs_t *lfs, const char *path) {
if (err) { if (err) {
return err; return err;
} }
// stickynotes don't really exist // if we find a stickynote, check to see if there are any open
if (tag == LFSR_TAG_STICKYNOTE) { // in-sync file handles to decide if it really exists
if (tag == LFSR_TAG_STICKYNOTE
&& !lfsr_omdir_ismidopen(lfs, mdir.mid,
~(LFS_o_ZOMBIE | LFS_O_DESYNC))) {
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
// we can't remove unknown types or else we may leak resources // we can't remove unknown types or else we may leak resources
if (tag != LFSR_TAG_REG && tag != LFSR_TAG_DIR) { if (tag != LFSR_TAG_REG
&& tag != LFSR_TAG_DIR
&& tag != LFSR_TAG_STICKYNOTE) {
return LFS_ERR_NOTSUP; return LFS_ERR_NOTSUP;
} }
@@ -10526,12 +10538,17 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
if (err) { if (err) {
return err; return err;
} }
// stickynotes don't really exist // if we find a stickynote, check to see if there are any open
if (old_tag == LFSR_TAG_STICKYNOTE) { // in-sync file handles to decide if it really exists
if (old_tag == LFSR_TAG_STICKYNOTE
&& !lfsr_omdir_ismidopen(lfs, old_mdir.mid,
~(LFS_o_ZOMBIE | LFS_O_DESYNC))) {
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
// we can't rename unknown types or else we may leak resources // we can't rename unknown types or else we may leak resources
if (old_tag != LFSR_TAG_REG && old_tag != LFSR_TAG_DIR) { if (old_tag != LFSR_TAG_REG
&& old_tag != LFSR_TAG_DIR
&& old_tag != LFSR_TAG_STICKYNOTE) {
return LFS_ERR_NOTSUP; return LFS_ERR_NOTSUP;
} }
@@ -10571,15 +10588,26 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
return LFS_ERR_INVAL; return LFS_ERR_INVAL;
} }
// renaming different types is an error // we allow reg <-> stickynote renaming, but renaming a non-dir
// // to a dir and a dir to a non-dir is an error
// unless we found a stickynote, these don't really exist if (old_tag != LFSR_TAG_DIR && new_tag == LFSR_TAG_DIR) {
if (old_tag != new_tag && new_tag != LFSR_TAG_STICKYNOTE) { return LFS_ERR_ISDIR;
return (new_tag == LFSR_TAG_DIR) }
? LFS_ERR_ISDIR if (old_tag == LFSR_TAG_DIR
: (new_tag == LFSR_TAG_REG) && new_tag != LFSR_TAG_DIR
? LFS_ERR_NOTDIR // if we find a stickynote, check to see if there are
: LFS_ERR_NOTSUP; // any open in-sync file handles to decide if it really
// exists
&& (new_tag != LFSR_TAG_STICKYNOTE
|| lfsr_omdir_ismidopen(lfs, new_mdir.mid,
~(LFS_o_ZOMBIE | LFS_O_DESYNC)))) {
return LFS_ERR_NOTDIR;
}
// we can't rename unknown types or else we may leak resources
if (new_tag != LFSR_TAG_REG
&& new_tag != LFSR_TAG_DIR
&& new_tag != LFSR_TAG_STICKYNOTE) {
return LFS_ERR_NOTSUP;
} }
// renaming to ourself is a noop // renaming to ourself is a noop
@@ -10743,8 +10771,11 @@ int lfsr_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
if (err) { if (err) {
return err; return err;
} }
// stickynotes don't really exist // if we find a stickynote, check to see if there are any open
if (tag == LFSR_TAG_STICKYNOTE) { // in-sync file handles to decide if it really exists
if (tag == LFSR_TAG_STICKYNOTE
&& !lfsr_omdir_ismidopen(lfs, mdir.mid,
~(LFS_o_ZOMBIE | LFS_O_DESYNC))) {
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
@@ -10780,8 +10811,11 @@ int lfsr_dir_open(lfs_t *lfs, lfsr_dir_t *dir, const char *path) {
if (err) { if (err) {
return err; return err;
} }
// stickynotes don't really exist // if we find a stickynote, check to see if there are any open
if (tag == LFSR_TAG_STICKYNOTE) { // in-sync file handles to decide if it really exists
if (tag == LFSR_TAG_STICKYNOTE
&& !lfsr_omdir_ismidopen(lfs, mdir.mid,
~(LFS_o_ZOMBIE | LFS_O_DESYNC))) {
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
@@ -10884,8 +10918,11 @@ int lfsr_dir_read(lfs_t *lfs, lfsr_dir_t *dir, struct lfs_info *info) {
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
// skip stickynotes, we pretend these don't exist // if we find a stickynote, check to see if there are any open
if (tag == LFSR_TAG_STICKYNOTE) { // in-sync file handles to decide if it really exists
if (tag == LFSR_TAG_STICKYNOTE
&& !lfsr_omdir_ismidopen(lfs, dir->o.mdir.mid,
~(LFS_o_ZOMBIE | LFS_O_DESYNC))) {
dir->o.mdir.mid += 1; dir->o.mdir.mid += 1;
dir->pos += 1; dir->pos += 1;
continue; continue;
@@ -10997,8 +11034,11 @@ static int lfsr_lookupattr(lfs_t *lfs, const char *path, uint8_t type,
if (err) { if (err) {
return err; return err;
} }
// stickynotes don't really exist // if we find a stickynote, check to see if there are any open
if (tag == LFSR_TAG_STICKYNOTE) { // in-sync file handles to decide if it really exists
if (tag == LFSR_TAG_STICKYNOTE
&& !lfsr_omdir_ismidopen(lfs, mdir_->mid,
~(LFS_o_ZOMBIE | LFS_O_DESYNC))) {
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
@@ -11333,8 +11373,13 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
} }
bool exists = err != LFS_ERR_NOENT; bool exists = err != LFS_ERR_NOENT;
// creating a new entry? // creating a new entry? if we find a stickynote, check to see if
if (!exists || tag == LFSR_TAG_STICKYNOTE) { // there are any open in-sync file handles to decide if it really
// exists
if (!exists
|| (tag == LFSR_TAG_STICKYNOTE
&& !lfsr_omdir_ismidopen(lfs, file->b.o.mdir.mid,
~(LFS_o_ZOMBIE | LFS_O_DESYNC)))) {
if (!lfsr_o_iscreat(flags)) { if (!lfsr_o_iscreat(flags)) {
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
@@ -11345,19 +11390,6 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
return LFS_ERR_NOTDIR; return LFS_ERR_NOTDIR;
} }
// if we're EXCL and we found a stickynote, check if the file
// is open and not zombied/desynced
//
// we error here even though the file isn't created yet so
// EXCL only lets one create through (ignoring desync+sync
// shenanigans)
if (exists
&& lfsr_o_isexcl(flags)
&& lfsr_omdir_ismidopen(lfs, file->b.o.mdir.mid,
~(LFS_o_ZOMBIE | LFS_O_DESYNC))) {
return LFS_ERR_EXIST;
}
// create a stickynote entry if we don't have one, this reserves the // create a stickynote entry if we don't have one, this reserves the
// mid until first sync // mid until first sync
if (!exists) { if (!exists) {
@@ -11385,11 +11417,6 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
} }
} }
} }
// mark as uncreated and unsynced, we need to convert to reg file
// on first sync
file->b.o.flags |= LFS_o_UNCREAT | LFS_o_UNSYNC;
} else { } else {
// wanted to create a new entry? // wanted to create a new entry?
if (lfsr_o_isexcl(flags)) { if (lfsr_o_isexcl(flags)) {
@@ -11397,13 +11424,19 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
} }
// wrong type? // wrong type?
if (tag != LFSR_TAG_REG) { if (tag != LFSR_TAG_REG && tag != LFSR_TAG_STICKYNOTE) {
return (tag == LFSR_TAG_DIR) return (tag == LFSR_TAG_DIR)
? LFS_ERR_ISDIR ? LFS_ERR_ISDIR
: LFS_ERR_NOTSUP; : LFS_ERR_NOTSUP;
} }
} }
// if stickynote, mark as uncreated and unsynced, we need to convert
// to reg file on first sync
if (!exists || tag == LFSR_TAG_STICKYNOTE) {
file->b.o.flags |= LFS_o_UNCREAT | LFS_o_UNSYNC;
}
// allocate cache if necessary // allocate cache if necessary
if (file->cfg->cache_buffer) { if (file->cfg->cache_buffer) {
file->cache.buffer = file->cfg->cache_buffer; file->cache.buffer = file->cfg->cache_buffer;
+1 -1
View File
@@ -113,10 +113,10 @@ enum lfs_type {
// file types // file types
LFS_TYPE_REG = 1, LFS_TYPE_REG = 1,
LFS_TYPE_DIR = 2, LFS_TYPE_DIR = 2,
LFS_TYPE_STICKYNOTE = 5,
// internally used types, don't use these // internally used types, don't use these
LFS_TYPE_BOOKMARK = 4, LFS_TYPE_BOOKMARK = 4,
LFS_TYPE_STICKYNOTE = 5,
LFS_TYPE_TRAVERSAL = 9, LFS_TYPE_TRAVERSAL = 9,
}; };
+967 -423
View File
File diff suppressed because it is too large Load Diff
+380 -190
View File
@@ -3548,11 +3548,12 @@ code = '''
// set up a simulation to compare against // set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t)); uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
bool *sim_isstickys = malloc(N*sizeof(bool));
lfs_size_t sim_size = 0; lfs_size_t sim_size = 0;
typedef struct sim_file { typedef struct sim_file {
lfs_size_t x; lfs_size_t x;
bool uncreat; bool sticky;
bool zombie; bool zombie;
uint32_t prng; uint32_t prng;
lfsr_file_t file; lfsr_file_t file;
@@ -3639,27 +3640,25 @@ code = '''
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// already exists? // already exists?
bool uncreat = true; bool exist = false;
uint32_t wprng = 0; uint32_t wprng = 0;
bool sticky = true;
for (lfs_size_t j = 0; j < sim_size; j++) { for (lfs_size_t j = 0; j < sim_size; j++) {
if (sim[j] == x) { if (sim[j] == x) {
uncreat = false; exist = true;
wprng = sim_prngs[j]; wprng = sim_prngs[j];
sticky = sim_isstickys[j];
break; break;
} }
} }
// choose a random seed if we don't exist // choose a random seed if we don't exist
if (uncreat) { if (!exist) {
wprng = TEST_PRNG(&prng); wprng = TEST_PRNG(&prng);
sticky = true;
} }
// open in our sim
lfs_size_t j = sim_file_count; lfs_size_t j = sim_file_count;
sim_files[j] = malloc(sizeof(sim_file_t)); sim_files[j] = malloc(sizeof(sim_file_t));
sim_files[j]->x = x;
sim_files[j]->uncreat = uncreat;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
// open the actual file // open the actual file
char name[256]; char name[256];
@@ -3668,24 +3667,58 @@ code = '''
LFS_O_RDWR | LFS_O_CREAT); LFS_O_RDWR | LFS_O_CREAT);
assert(!err || err == LFS_ERR_NOSPC); assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS_ERR_NOSPC) {
free(sim_files[j]);
goto corrupt_mounted; goto corrupt_mounted;
} }
sim_file_count++;
// write some initial data if we don't exist // write some initial data if we don't exist
if (uncreat) { if (!exist || sticky) {
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
} }
lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file, lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file,
wbuf, SIZE); wbuf, SIZE);
assert(d == SIZE || d == LFS_ERR_NOSPC); assert(d == SIZE || d == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (d == LFS_ERR_NOSPC) {
lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
free(sim_files[j]);
goto corrupt_mounted; goto corrupt_mounted;
} }
} }
// open in our sim
sim_files[j]->x = x;
sim_files[j]->sticky = sticky;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
}
break;
}
}
// write/rewrite a file? // write/rewrite a file?
} else if (op == 1) { } else if (op == 1) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -3697,44 +3730,12 @@ code = '''
// choose a random seed // choose a random seed
uint32_t wprng = TEST_PRNG(&prng); uint32_t wprng = TEST_PRNG(&prng);
// update sim
sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) {
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
}
break;
}
}
// update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
sim_files[k]->uncreat = false;
sim_files[k]->prng = wprng;
}
}
}
// write to the file // write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0; lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
} }
lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file, lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file,
wbuf, SIZE); wbuf, SIZE);
@@ -3751,6 +3752,31 @@ code = '''
goto corrupt_mounted; goto corrupt_mounted;
} }
// update sim
sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) {
// update in our sim
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
// no longer sticky
sim_isstickys[k] = false;
break;
}
}
// update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
// new prng
sim_files[k]->prng = wprng;
// no longer sticky
sim_files[k]->sticky = false;
}
}
}
// close a file? // close a file?
} else if (op == 2) { } else if (op == 2) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -3758,6 +3784,9 @@ code = '''
} }
// choose a random file handle // choose a random file handle
lfs_size_t j = TEST_PRNG(&prng) % sim_file_count; lfs_size_t j = TEST_PRNG(&prng) % sim_file_count;
lfs_size_t x = sim_files[j]->x;
bool sticky = sim_files[j]->sticky;
bool zombie = sim_files[j]->zombie;
// this doesn't really test anything, but if we don't close // this doesn't really test anything, but if we don't close
// files eventually everything will end up zombies // files eventually everything will end up zombies
@@ -3765,12 +3794,41 @@ code = '''
// close the file without affected disk // close the file without affected disk
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0; lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
// clobber closed files to try to catch lingering references
memset(&sim_files[j]->file, 0xcc, sizeof(lfsr_file_t));
// remove from list // remove from list
free(sim_files[j]); free(sim_files[j]);
sim_files[j] = sim_files[sim_file_count-1]; sim_files[j] = sim_files[sim_file_count-1];
sim_file_count -= 1; sim_file_count -= 1;
// update our sim
if (sticky && !zombie) {
// orphaned?
bool orphan = true;
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
orphan = false;
}
}
// if we were never synced, delete from sim
if (orphan) {
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
memmove(&sim[k], &sim[k+1],
(sim_size-(k+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[k], &sim_prngs[k+1],
(sim_size-(k+1))*sizeof(uint32_t));
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
(sim_size-(k+1))*sizeof(bool));
sim_size -= 1;
break;
}
}
}
}
// remove a file? // remove a file?
} else if (op == 3) { } else if (op == 3) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -3780,20 +3838,6 @@ code = '''
lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t j = TEST_PRNG(&prng) % sim_size;
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
// delete from our sim
memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t));
sim_size -= 1;
// mark any related sim files as zombied
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x) {
sim_files[k]->zombie = true;
}
}
// delete this file // delete this file
char name[256]; char name[256];
sprintf(name, "batman%03x", x); sprintf(name, "batman%03x", x);
@@ -3803,6 +3847,22 @@ code = '''
goto corrupt_mounted; goto corrupt_mounted;
} }
// delete from our sim
memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
sim_size -= 1;
// mark any related sim files as zombied
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x) {
sim_files[k]->zombie = true;
}
}
// rename a file? // rename a file?
} else if (op == 4) { } else if (op == 4) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -3814,6 +3874,18 @@ code = '''
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
lfs_size_t y = TEST_PRNG(&prng) % N; lfs_size_t y = TEST_PRNG(&prng) % N;
uint32_t wprng = sim_prngs[j]; uint32_t wprng = sim_prngs[j];
bool sticky = sim_isstickys[j];
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
int err = lfsr_rename(&lfs, old_name, new_name);
assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
goto corrupt_mounted;
}
// update our sim // update our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
@@ -3825,12 +3897,15 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
// update the prng // update the prng/sticky
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
// just renaming // just renaming
} else { } else {
// first delete // first delete
@@ -3838,6 +3913,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
@@ -3846,8 +3923,11 @@ code = '''
(sim_size-k)*sizeof(lfs_size_t)); (sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k], memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t)); (sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
sim[k] = y; sim[k] = y;
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
} }
break; break;
} }
@@ -3864,17 +3944,6 @@ code = '''
sim_files[k]->zombie = true; sim_files[k]->zombie = true;
} }
} }
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
int err = lfsr_rename(&lfs, old_name, new_name);
assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
goto corrupt_mounted;
}
} }
} }
@@ -3885,8 +3954,13 @@ code = '''
struct lfs_info info; struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0; lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_REG); if (sim_isstickys[j]) {
assert(info.size == SIZE); assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else {
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
} }
lfsr_dir_t dir; lfsr_dir_t dir;
@@ -3905,8 +3979,13 @@ code = '''
sprintf(name, "batman%03x", sim[j]); sprintf(name, "batman%03x", sim[j]);
lfsr_dir_read(&lfs, &dir, &info) => 0; lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_REG); if (sim_isstickys[j]) {
assert(info.size == SIZE); assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else {
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
} }
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0; lfsr_dir_close(&lfs, &dir) => 0;
@@ -3924,14 +4003,19 @@ code = '''
} }
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfs_ssize_t d = lfsr_file_read(&lfs, &file, rbuf, SIZE); if (sim_isstickys[j]) {
assert(d == SIZE lfsr_file_read(&lfs, &file, rbuf, SIZE) => 0;
|| (d == LFS_ERR_CORRUPT && (METHOD == 2 || METHOD == 3))); } else {
if (d == LFS_ERR_CORRUPT) { lfs_ssize_t d = lfsr_file_read(&lfs, &file, rbuf, SIZE);
lfsr_file_close(&lfs, &file) => 0; assert(d == SIZE
goto corrupt_mounted; || (d == LFS_ERR_CORRUPT
&& (METHOD == 2 || METHOD == 3)));
if (d == LFS_ERR_CORRUPT) {
lfsr_file_close(&lfs, &file) => 0;
goto corrupt_mounted;
}
assert(memcmp(rbuf, wbuf, SIZE) == 0);
} }
assert(memcmp(rbuf, wbuf, SIZE) == 0);
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;
} }
@@ -3947,7 +4031,8 @@ code = '''
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfs_ssize_t d = lfsr_file_read(&lfs, &sim_files[j]->file, rbuf, SIZE); lfs_ssize_t d = lfsr_file_read(&lfs, &sim_files[j]->file, rbuf, SIZE);
assert(d == SIZE assert(d == SIZE
|| (d == LFS_ERR_CORRUPT && (METHOD == 2 || METHOD == 3))); || (d == LFS_ERR_CORRUPT
&& (METHOD == 2 || METHOD == 3)));
if (d == LFS_ERR_CORRUPT) { if (d == LFS_ERR_CORRUPT) {
goto corrupt_mounted; goto corrupt_mounted;
} }
@@ -3958,6 +4043,7 @@ corrupt_mounted:;
// clean up sim/lfs // clean up sim/lfs
free(sim); free(sim);
free(sim_prngs); free(sim_prngs);
free(sim_isstickys);
for (lfs_size_t j = 0; j < sim_file_count; j++) { for (lfs_size_t j = 0; j < sim_file_count; j++) {
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0; lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
@@ -4054,12 +4140,13 @@ code = '''
// set up a simulation to compare against // set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t)); uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
bool *sim_isstickys = malloc(N*sizeof(bool));
bool *sim_isdirs = malloc(N*sizeof(bool)); bool *sim_isdirs = malloc(N*sizeof(bool));
lfs_size_t sim_size = 0; lfs_size_t sim_size = 0;
typedef struct sim_file { typedef struct sim_file {
lfs_size_t x; lfs_size_t x;
bool uncreat; bool sticky;
bool zombie; bool zombie;
uint32_t prng; uint32_t prng;
lfsr_file_t file; lfsr_file_t file;
@@ -4146,30 +4233,28 @@ code = '''
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// already exists? // already exists?
bool uncreat = true; bool exist = true;
uint32_t wprng = 0; uint32_t wprng = 0;
bool sticky = true;
for (lfs_size_t j = 0; j < sim_size; j++) { for (lfs_size_t j = 0; j < sim_size; j++) {
if (sim[j] == x) { if (sim[j] == x) {
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
goto nonsense; goto nonsense;
} }
uncreat = false; exist = true;
wprng = sim_prngs[j]; wprng = sim_prngs[j];
sticky = sim_isstickys[j];
break; break;
} }
} }
// choose a random seed if we don't exist // choose a random seed if we don't exist
if (uncreat) { if (!exist) {
wprng = TEST_PRNG(&prng); wprng = TEST_PRNG(&prng);
sticky = true;
} }
// open in our sim
lfs_size_t j = sim_file_count; lfs_size_t j = sim_file_count;
sim_files[j] = malloc(sizeof(sim_file_t)); sim_files[j] = malloc(sizeof(sim_file_t));
sim_files[j]->x = x;
sim_files[j]->uncreat = uncreat;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
// open the actual file // open the actual file
char name[256]; char name[256];
@@ -4178,24 +4263,61 @@ code = '''
LFS_O_RDWR | LFS_O_CREAT); LFS_O_RDWR | LFS_O_CREAT);
assert(!err || err == LFS_ERR_NOSPC); assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS_ERR_NOSPC) {
free(sim_files[j]);
goto corrupt_mounted; goto corrupt_mounted;
} }
sim_file_count++;
// write some initial data if we don't exist // write some initial data if we don't exist
if (uncreat) { if (!exist || sticky) {
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
} }
lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file, lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file,
wbuf, SIZE); wbuf, SIZE);
assert(d == SIZE || d == LFS_ERR_NOSPC); assert(d == SIZE || d == LFS_ERR_NOSPC);
if (d == LFS_ERR_NOSPC) { if (d == LFS_ERR_NOSPC) {
lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
free(sim_files[j]);
goto corrupt_mounted; goto corrupt_mounted;
} }
} }
// open in our sim
sim_files[j]->x = x;
sim_files[j]->sticky = sticky;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
sim_isdirs[k] = false;
}
break;
}
}
// write/rewrite a file? // write/rewrite a file?
} else if (op == 1) { } else if (op == 1) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -4207,47 +4329,12 @@ code = '''
// choose a random seed // choose a random seed
uint32_t wprng = TEST_PRNG(&prng); uint32_t wprng = TEST_PRNG(&prng);
// update sim
sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) {
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isdirs[k] = false;
}
break;
}
}
// update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
sim_files[k]->uncreat = false;
sim_files[k]->prng = wprng;
}
}
}
// write to the file // write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0; lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
} }
lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file, lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file,
wbuf, SIZE); wbuf, SIZE);
@@ -4264,6 +4351,31 @@ code = '''
goto corrupt_mounted; goto corrupt_mounted;
} }
// update sim
sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) {
// update in our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// new prng
sim_prngs[k] = wprng;
// no longer sticky
sim_isstickys[k] = false;
break;
}
}
// update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
// new prng
sim_files[k]->prng = wprng;
// no longer sticky
sim_files[k]->sticky = false;
}
}
}
// close a file? // close a file?
} else if (op == 2) { } else if (op == 2) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -4271,6 +4383,9 @@ code = '''
} }
// choose a random file handle // choose a random file handle
lfs_size_t j = TEST_PRNG(&prng) % sim_file_count; lfs_size_t j = TEST_PRNG(&prng) % sim_file_count;
lfs_size_t x = sim_files[j]->x;
lfs_size_t sticky = sim_files[j]->sticky;
lfs_size_t zombie = sim_files[j]->zombie;
// this doesn't really test anything, but if we don't close // this doesn't really test anything, but if we don't close
// files eventually everything will end up zombies // files eventually everything will end up zombies
@@ -4278,12 +4393,43 @@ code = '''
// close the file without affected disk // close the file without affected disk
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0; lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
// clobber closed files to try to catch lingering references
memset(&sim_files[j]->file, 0xcc, sizeof(lfsr_file_t));
// remove from list // remove from list
free(sim_files[j]); free(sim_files[j]);
sim_files[j] = sim_files[sim_file_count-1]; sim_files[j] = sim_files[sim_file_count-1];
sim_file_count -= 1; sim_file_count -= 1;
// update our sim
if (sticky && !zombie) {
// orphaned?
bool orphan = true;
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
orphan = false;
}
}
// if we were never synced, delete from sim
if (orphan) {
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
memmove(&sim[k], &sim[k+1],
(sim_size-(k+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[k], &sim_prngs[k+1],
(sim_size-(k+1))*sizeof(uint32_t));
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
(sim_size-(k+1))*sizeof(bool));
memmove(&sim_isdirs[k], &sim_isdirs[k+1],
(sim_size-(k+1))*sizeof(bool));
sim_size -= 1;
break;
}
}
}
}
// remove a file? // remove a file?
} else if (op == 3) { } else if (op == 3) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -4293,11 +4439,22 @@ code = '''
lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t j = TEST_PRNG(&prng) % sim_size;
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
int err = lfsr_remove(&lfs, name);
assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
goto corrupt_mounted;
}
// delete from our sim // delete from our sim
memmove(&sim[j], &sim[j+1], memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
@@ -4309,15 +4466,6 @@ code = '''
} }
} }
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
int err = lfsr_remove(&lfs, name);
assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
goto corrupt_mounted;
}
// rename a file? // rename a file?
} else if (op == 4) { } else if (op == 4) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -4329,31 +4477,55 @@ code = '''
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
lfs_size_t y = TEST_PRNG(&prng) % N; lfs_size_t y = TEST_PRNG(&prng) % N;
uint32_t wprng = sim_prngs[j]; uint32_t wprng = sim_prngs[j];
bool isdir = sim_isdirs[j]; bool sticky = sim_isstickys[j];
bool dir = sim_isdirs[j];
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= y) {
// renaming and replacing
if (k < sim_size && sim[k] == y && x != y) {
// type mismatch?
if (sim_isdirs[k] != dir) {
goto nonsense;
}
}
break;
}
}
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
int err = lfsr_rename(&lfs, old_name, new_name);
assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
goto corrupt_mounted;
}
// update our sim // update our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= y) { if (k >= sim_size || sim[k] >= y) {
// renaming and replacing // renaming and replacing
if (k < sim_size && sim[k] == y && x != y) { if (k < sim_size && sim[k] == y && x != y) {
// type mismatch?
if (sim_isdirs[k] != isdir) {
goto nonsense;
}
// delete the original entry // delete the original entry
memmove(&sim[j], &sim[j+1], memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
// update the prng // update the prng/sticky/dir
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
sim_isdirs[k] = dir;
// just renaming // just renaming
} else { } else {
// first delete // first delete
@@ -4361,6 +4533,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
if (k > j) { if (k > j) {
@@ -4371,11 +4545,14 @@ code = '''
(sim_size-k)*sizeof(lfs_size_t)); (sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k], memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t)); (sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k], memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool)); (sim_size-k)*sizeof(bool));
sim[k] = y; sim[k] = y;
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isdirs[k] = isdir; sim_isstickys[k] = sticky;
sim_isdirs[k] = dir;
} }
break; break;
} }
@@ -4393,52 +4570,21 @@ code = '''
} }
} }
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
int err = lfsr_rename(&lfs, old_name, new_name);
assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
goto corrupt_mounted;
}
// toss a directory into the mix // toss a directory into the mix
} else if (op == 5) { } else if (op == 5) {
// choose a pseudo-random number // choose a pseudo-random number
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// insert into our sim, use negative numbers for dirs
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (k >= sim_size || sim[k] >= x) {
// already seen? // already seen?
if (k < sim_size && sim[k] == x) { if (k < sim_size && sim[k] == x) {
goto nonsense; goto nonsense;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = 0;
sim_isdirs[k] = true;
} }
break; break;
} }
} }
// mark any related sim files as zombied
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x) {
sim_files[k]->zombie = true;
}
}
// make the directory // make the directory
char name[256]; char name[256];
sprintf(name, "batman%03x", x); sprintf(name, "batman%03x", x);
@@ -4447,6 +4593,33 @@ code = '''
if (err == LFS_ERR_NOSPC) { if (err == LFS_ERR_NOSPC) {
goto corrupt_mounted; goto corrupt_mounted;
} }
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = 0;
sim_isdirs[k] = true;
break;
}
}
// mark any related sim files as zombied
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x) {
sim_files[k]->zombie = true;
}
}
} }
} }
@@ -4459,6 +4632,10 @@ code = '''
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(info.size == 0);
} else if (sim_isstickys[j]) {
assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else { } else {
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
@@ -4483,6 +4660,10 @@ code = '''
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(info.size == 0);
} else if (sim_isstickys[j]) {
assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else { } else {
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
@@ -4512,14 +4693,19 @@ code = '''
} }
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfs_ssize_t d = lfsr_file_read(&lfs, &file, rbuf, SIZE); if (sim_isstickys[j]) {
assert(d == SIZE lfsr_file_read(&lfs, &file, rbuf, SIZE) => 0;
|| (d == LFS_ERR_CORRUPT && (METHOD == 2 || METHOD == 3))); } else {
if (d == LFS_ERR_CORRUPT) { lfs_ssize_t d = lfsr_file_read(&lfs, &file, rbuf, SIZE);
lfsr_file_close(&lfs, &file) => 0; assert(d == SIZE
goto corrupt_mounted; || (d == LFS_ERR_CORRUPT
&& (METHOD == 2 || METHOD == 3)));
if (d == LFS_ERR_CORRUPT) {
lfsr_file_close(&lfs, &file) => 0;
goto corrupt_mounted;
}
assert(memcmp(rbuf, wbuf, SIZE) == 0);
} }
assert(memcmp(rbuf, wbuf, SIZE) == 0);
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;
} }
} }
@@ -4536,7 +4722,8 @@ code = '''
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfs_ssize_t d = lfsr_file_read(&lfs, &sim_files[j]->file, rbuf, SIZE); lfs_ssize_t d = lfsr_file_read(&lfs, &sim_files[j]->file, rbuf, SIZE);
assert(d == SIZE assert(d == SIZE
|| (d == LFS_ERR_CORRUPT && (METHOD == 2 || METHOD == 3))); || (d == LFS_ERR_CORRUPT
&& (METHOD == 2 || METHOD == 3)));
if (d == LFS_ERR_CORRUPT) { if (d == LFS_ERR_CORRUPT) {
goto corrupt_mounted; goto corrupt_mounted;
} }
@@ -4547,6 +4734,8 @@ corrupt_mounted:;
// clean up sim/lfs // clean up sim/lfs
free(sim); free(sim);
free(sim_prngs); free(sim_prngs);
free(sim_isstickys);
free(sim_isdirs);
for (lfs_size_t j = 0; j < sim_file_count; j++) { for (lfs_size_t j = 0; j < sim_file_count; j++) {
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0; lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
@@ -4554,6 +4743,7 @@ corrupt_mounted:;
} }
free(sim_files); free(sim_files);
lfsr_unmount(&lfs) => 0; lfsr_unmount(&lfs) => 0;
// how many errors did we survive? // how many errors did we survive?
printf("survived %d block errors!\n", (int)(i/PERIOD)); printf("survived %d block errors!\n", (int)(i/PERIOD));
''' '''
+365 -180
View File
@@ -754,11 +754,12 @@ code = '''
// set up a simulation to compare against // set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t)); uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
bool *sim_isstickys = malloc(N*sizeof(bool));
lfs_size_t sim_size = 0; lfs_size_t sim_size = 0;
typedef struct sim_file { typedef struct sim_file {
lfs_size_t x; lfs_size_t x;
bool uncreat; bool sticky;
bool zombie; bool zombie;
uint32_t prng; uint32_t prng;
lfsr_file_t file; lfsr_file_t file;
@@ -781,27 +782,25 @@ code = '''
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// already exists? // already exists?
bool uncreat = true; bool exist = false;
uint32_t wprng = 0; uint32_t wprng = 0;
bool sticky = true;
for (lfs_size_t j = 0; j < sim_size; j++) { for (lfs_size_t j = 0; j < sim_size; j++) {
if (sim[j] == x) { if (sim[j] == x) {
uncreat = false; exist = true;
wprng = sim_prngs[j]; wprng = sim_prngs[j];
sticky = sim_isstickys[j];
break; break;
} }
} }
// choose a random seed if we don't exist // choose a random seed if we don't exist
if (uncreat) { if (!exist) {
wprng = TEST_PRNG(&prng); wprng = TEST_PRNG(&prng);
sticky = true;
} }
// open in our sim
lfs_size_t j = sim_file_count; lfs_size_t j = sim_file_count;
sim_files[j] = malloc(sizeof(sim_file_t)); sim_files[j] = malloc(sizeof(sim_file_t));
sim_files[j]->x = x;
sim_files[j]->uncreat = uncreat;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
// open the actual file // open the actual file
char name[256]; char name[256];
@@ -810,24 +809,58 @@ code = '''
LFS_O_RDWR | LFS_O_CREAT); LFS_O_RDWR | LFS_O_CREAT);
assert(!err || err == LFS_ERR_NOSPC); assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS_ERR_NOSPC) {
free(sim_files[j]);
goto dead; goto dead;
} }
sim_file_count++;
// write some initial data if we don't exist // write some initial data if we don't exist
if (uncreat) { if (!exist || sticky) {
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
} }
lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file, lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file,
wbuf, SIZE); wbuf, SIZE);
assert(d == SIZE || d == LFS_ERR_NOSPC); assert(d == SIZE || d == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (d == LFS_ERR_NOSPC) {
lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
free(sim_files[j]);
goto dead; goto dead;
} }
} }
// open in our sim
sim_files[j]->x = x;
sim_files[j]->sticky = sticky;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
}
break;
}
}
// write/rewrite a file? // write/rewrite a file?
} else if (op == 1) { } else if (op == 1) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -839,44 +872,12 @@ code = '''
// choose a random seed // choose a random seed
uint32_t wprng = TEST_PRNG(&prng); uint32_t wprng = TEST_PRNG(&prng);
// update sim
sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) {
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
}
break;
}
}
// update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
sim_files[k]->uncreat = false;
sim_files[k]->prng = wprng;
}
}
}
// write to the file // write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0; lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
} }
lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file, lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file,
wbuf, SIZE); wbuf, SIZE);
@@ -891,6 +892,31 @@ code = '''
goto dead; goto dead;
} }
// update sim
sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) {
// update in our sim
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
// no longer sticky
sim_isstickys[k] = false;
break;
}
}
// update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
// new prng
sim_files[k]->prng = wprng;
// no longer sticky
sim_files[k]->sticky = false;
}
}
}
// close a file? // close a file?
} else if (op == 2) { } else if (op == 2) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -898,6 +924,9 @@ code = '''
} }
// choose a random file handle // choose a random file handle
lfs_size_t j = TEST_PRNG(&prng) % sim_file_count; lfs_size_t j = TEST_PRNG(&prng) % sim_file_count;
lfs_size_t x = sim_files[j]->x;
bool sticky = sim_files[j]->sticky;
bool zombie = sim_files[j]->zombie;
// this doesn't really test anything, but if we don't close // this doesn't really test anything, but if we don't close
// files eventually everything will end up zombies // files eventually everything will end up zombies
@@ -905,12 +934,41 @@ code = '''
// close the file without affected disk // close the file without affected disk
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0; lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
// clobber closed files to try to catch lingering references
memset(&sim_files[j]->file, 0xcc, sizeof(lfsr_file_t));
// remove from list // remove from list
free(sim_files[j]); free(sim_files[j]);
sim_files[j] = sim_files[sim_file_count-1]; sim_files[j] = sim_files[sim_file_count-1];
sim_file_count -= 1; sim_file_count -= 1;
// update our sim
if (sticky && !zombie) {
// orphaned?
bool orphan = true;
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
orphan = false;
}
}
// if we were never synced, delete from sim
if (orphan) {
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
memmove(&sim[k], &sim[k+1],
(sim_size-(k+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[k], &sim_prngs[k+1],
(sim_size-(k+1))*sizeof(uint32_t));
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
(sim_size-(k+1))*sizeof(bool));
sim_size -= 1;
break;
}
}
}
}
// remove a file? // remove a file?
} else if (op == 3) { } else if (op == 3) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -920,20 +978,6 @@ code = '''
lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t j = TEST_PRNG(&prng) % sim_size;
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
// delete from our sim
memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t));
sim_size -= 1;
// mark any related sim files as zombied
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x) {
sim_files[k]->zombie = true;
}
}
// delete this file // delete this file
char name[256]; char name[256];
sprintf(name, "batman%03x", x); sprintf(name, "batman%03x", x);
@@ -943,6 +987,22 @@ code = '''
goto dead; goto dead;
} }
// delete from our sim
memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
sim_size -= 1;
// mark any related sim files as zombied
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x) {
sim_files[k]->zombie = true;
}
}
// rename a file? // rename a file?
} else if (op == 4) { } else if (op == 4) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -954,6 +1014,18 @@ code = '''
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
lfs_size_t y = TEST_PRNG(&prng) % N; lfs_size_t y = TEST_PRNG(&prng) % N;
uint32_t wprng = sim_prngs[j]; uint32_t wprng = sim_prngs[j];
bool sticky = sim_isstickys[j];
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
int err = lfsr_rename(&lfs, old_name, new_name);
assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
goto dead;
}
// update our sim // update our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
@@ -965,12 +1037,15 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
// update the prng // update the prng/sticky
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
// just renaming // just renaming
} else { } else {
// first delete // first delete
@@ -978,6 +1053,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
@@ -986,8 +1063,11 @@ code = '''
(sim_size-k)*sizeof(lfs_size_t)); (sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k], memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t)); (sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
sim[k] = y; sim[k] = y;
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
} }
break; break;
} }
@@ -1004,17 +1084,6 @@ code = '''
sim_files[k]->zombie = true; sim_files[k]->zombie = true;
} }
} }
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
int err = lfsr_rename(&lfs, old_name, new_name);
assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
goto dead;
}
} }
// check our simulation every power-of-2 ops // check our simulation every power-of-2 ops
@@ -1026,8 +1095,13 @@ code = '''
struct lfs_info info; struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0; lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_REG); if (sim_isstickys[j]) {
assert(info.size == SIZE); assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else {
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
} }
lfsr_dir_t dir; lfsr_dir_t dir;
@@ -1046,8 +1120,13 @@ code = '''
sprintf(name, "batman%03x", sim[j]); sprintf(name, "batman%03x", sim[j]);
lfsr_dir_read(&lfs, &dir, &info) => 0; lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_REG); if (sim_isstickys[j]) {
assert(info.size == SIZE); assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else {
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
} }
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0; lfsr_dir_close(&lfs, &dir) => 0;
@@ -1065,8 +1144,12 @@ code = '''
} }
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; if (sim_isstickys[j]) {
assert(memcmp(rbuf, wbuf, SIZE) == 0); lfsr_file_read(&lfs, &file, rbuf, SIZE) => 0;
} else {
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
}
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;
} }
@@ -1080,8 +1163,8 @@ code = '''
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0; lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfsr_file_read(&lfs, &sim_files[j]->file, lfsr_file_read(&lfs, &sim_files[j]->file, rbuf, SIZE)
rbuf, SIZE) => SIZE; => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0); assert(memcmp(rbuf, wbuf, SIZE) == 0);
} }
} }
@@ -1091,6 +1174,7 @@ code = '''
// clean up sim/lfs // clean up sim/lfs
free(sim); free(sim);
free(sim_prngs); free(sim_prngs);
free(sim_isstickys);
for (lfs_size_t j = 0; j < sim_file_count; j++) { for (lfs_size_t j = 0; j < sim_file_count; j++) {
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0; lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
@@ -1176,12 +1260,13 @@ code = '''
// set up a simulation to compare against // set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t)); uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
bool *sim_isstickys = malloc(N*sizeof(bool));
bool *sim_isdirs = malloc(N*sizeof(bool)); bool *sim_isdirs = malloc(N*sizeof(bool));
lfs_size_t sim_size = 0; lfs_size_t sim_size = 0;
typedef struct sim_file { typedef struct sim_file {
lfs_size_t x; lfs_size_t x;
bool uncreat; bool sticky;
bool zombie; bool zombie;
uint32_t prng; uint32_t prng;
lfsr_file_t file; lfsr_file_t file;
@@ -1204,30 +1289,28 @@ code = '''
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// already exists? // already exists?
bool uncreat = true; bool exist = true;
uint32_t wprng = 0; uint32_t wprng = 0;
bool sticky = true;
for (lfs_size_t j = 0; j < sim_size; j++) { for (lfs_size_t j = 0; j < sim_size; j++) {
if (sim[j] == x) { if (sim[j] == x) {
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
goto nonsense; goto nonsense;
} }
uncreat = false; exist = true;
wprng = sim_prngs[j]; wprng = sim_prngs[j];
sticky = sim_isstickys[j];
break; break;
} }
} }
// choose a random seed if we don't exist // choose a random seed if we don't exist
if (uncreat) { if (!exist) {
wprng = TEST_PRNG(&prng); wprng = TEST_PRNG(&prng);
sticky = true;
} }
// open in our sim
lfs_size_t j = sim_file_count; lfs_size_t j = sim_file_count;
sim_files[j] = malloc(sizeof(sim_file_t)); sim_files[j] = malloc(sizeof(sim_file_t));
sim_files[j]->x = x;
sim_files[j]->uncreat = uncreat;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
// open the actual file // open the actual file
char name[256]; char name[256];
@@ -1236,24 +1319,61 @@ code = '''
LFS_O_RDWR | LFS_O_CREAT); LFS_O_RDWR | LFS_O_CREAT);
assert(!err || err == LFS_ERR_NOSPC); assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS_ERR_NOSPC) {
free(sim_files[j]);
goto dead; goto dead;
} }
sim_file_count++;
// write some initial data if we don't exist // write some initial data if we don't exist
if (uncreat) { if (!exist || sticky) {
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
} }
lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file, lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file,
wbuf, SIZE); wbuf, SIZE);
assert(d == SIZE || d == LFS_ERR_NOSPC); assert(d == SIZE || d == LFS_ERR_NOSPC);
if (d == LFS_ERR_NOSPC) { if (d == LFS_ERR_NOSPC) {
lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
free(sim_files[j]);
goto dead; goto dead;
} }
} }
// open in our sim
sim_files[j]->x = x;
sim_files[j]->sticky = sticky;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
sim_isdirs[k] = false;
}
break;
}
}
// write/rewrite a file? // write/rewrite a file?
} else if (op == 1) { } else if (op == 1) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -1265,47 +1385,12 @@ code = '''
// choose a random seed // choose a random seed
uint32_t wprng = TEST_PRNG(&prng); uint32_t wprng = TEST_PRNG(&prng);
// update sim
sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) {
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isdirs[k] = false;
}
break;
}
}
// update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
sim_files[k]->uncreat = false;
sim_files[k]->prng = wprng;
}
}
}
// write to the file // write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0; lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
} }
lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file, lfs_ssize_t d = lfsr_file_write(&lfs, &sim_files[j]->file,
wbuf, SIZE); wbuf, SIZE);
@@ -1320,6 +1405,31 @@ code = '''
goto dead; goto dead;
} }
// update sim
sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) {
// update in our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// new prng
sim_prngs[k] = wprng;
// no longer sticky
sim_isstickys[k] = false;
break;
}
}
// update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
// new prng
sim_files[k]->prng = wprng;
// no longer sticky
sim_files[k]->sticky = false;
}
}
}
// close a file? // close a file?
} else if (op == 2) { } else if (op == 2) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -1327,6 +1437,9 @@ code = '''
} }
// choose a random file handle // choose a random file handle
lfs_size_t j = TEST_PRNG(&prng) % sim_file_count; lfs_size_t j = TEST_PRNG(&prng) % sim_file_count;
lfs_size_t x = sim_files[j]->x;
lfs_size_t sticky = sim_files[j]->sticky;
lfs_size_t zombie = sim_files[j]->zombie;
// this doesn't really test anything, but if we don't close // this doesn't really test anything, but if we don't close
// files eventually everything will end up zombies // files eventually everything will end up zombies
@@ -1334,12 +1447,43 @@ code = '''
// close the file without affected disk // close the file without affected disk
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0; lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
// clobber closed files to try to catch lingering references
memset(&sim_files[j]->file, 0xcc, sizeof(lfsr_file_t));
// remove from list // remove from list
free(sim_files[j]); free(sim_files[j]);
sim_files[j] = sim_files[sim_file_count-1]; sim_files[j] = sim_files[sim_file_count-1];
sim_file_count -= 1; sim_file_count -= 1;
// update our sim
if (sticky && !zombie) {
// orphaned?
bool orphan = true;
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
orphan = false;
}
}
// if we were never synced, delete from sim
if (orphan) {
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
memmove(&sim[k], &sim[k+1],
(sim_size-(k+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[k], &sim_prngs[k+1],
(sim_size-(k+1))*sizeof(uint32_t));
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
(sim_size-(k+1))*sizeof(bool));
memmove(&sim_isdirs[k], &sim_isdirs[k+1],
(sim_size-(k+1))*sizeof(bool));
sim_size -= 1;
break;
}
}
}
}
// remove a file? // remove a file?
} else if (op == 3) { } else if (op == 3) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -1349,11 +1493,22 @@ code = '''
lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t j = TEST_PRNG(&prng) % sim_size;
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
int err = lfsr_remove(&lfs, name);
assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
goto dead;
}
// delete from our sim // delete from our sim
memmove(&sim[j], &sim[j+1], memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
@@ -1365,15 +1520,6 @@ code = '''
} }
} }
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
int err = lfsr_remove(&lfs, name);
assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
goto dead;
}
// rename a file? // rename a file?
} else if (op == 4) { } else if (op == 4) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -1385,31 +1531,55 @@ code = '''
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
lfs_size_t y = TEST_PRNG(&prng) % N; lfs_size_t y = TEST_PRNG(&prng) % N;
uint32_t wprng = sim_prngs[j]; uint32_t wprng = sim_prngs[j];
bool isdir = sim_isdirs[j]; bool sticky = sim_isstickys[j];
bool dir = sim_isdirs[j];
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= y) {
// renaming and replacing
if (k < sim_size && sim[k] == y && x != y) {
// type mismatch?
if (sim_isdirs[k] != dir) {
goto nonsense;
}
}
break;
}
}
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
int err = lfsr_rename(&lfs, old_name, new_name);
assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
goto dead;
}
// update our sim // update our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= y) { if (k >= sim_size || sim[k] >= y) {
// renaming and replacing // renaming and replacing
if (k < sim_size && sim[k] == y && x != y) { if (k < sim_size && sim[k] == y && x != y) {
// type mismatch?
if (sim_isdirs[k] != isdir) {
goto nonsense;
}
// delete the original entry // delete the original entry
memmove(&sim[j], &sim[j+1], memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
// update the prng // update the prng/sticky/dir
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
sim_isdirs[k] = dir;
// just renaming // just renaming
} else { } else {
// first delete // first delete
@@ -1417,6 +1587,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
if (k > j) { if (k > j) {
@@ -1427,11 +1599,14 @@ code = '''
(sim_size-k)*sizeof(lfs_size_t)); (sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k], memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t)); (sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k], memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool)); (sim_size-k)*sizeof(bool));
sim[k] = y; sim[k] = y;
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isdirs[k] = isdir; sim_isstickys[k] = sticky;
sim_isdirs[k] = dir;
} }
break; break;
} }
@@ -1449,52 +1624,21 @@ code = '''
} }
} }
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
int err = lfsr_rename(&lfs, old_name, new_name);
assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
goto dead;
}
// toss a directory into the mix // toss a directory into the mix
} else if (op == 5) { } else if (op == 5) {
// choose a pseudo-random number // choose a pseudo-random number
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// insert into our sim, use negative numbers for dirs
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (k >= sim_size || sim[k] >= x) {
// already seen? // already seen?
if (k < sim_size && sim[k] == x) { if (k < sim_size && sim[k] == x) {
goto nonsense; goto nonsense;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = 0;
sim_isdirs[k] = true;
} }
break; break;
} }
} }
// mark any related sim files as zombied
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x) {
sim_files[k]->zombie = true;
}
}
// make the directory // make the directory
char name[256]; char name[256];
sprintf(name, "batman%03x", x); sprintf(name, "batman%03x", x);
@@ -1503,6 +1647,33 @@ code = '''
if (err == LFS_ERR_NOSPC) { if (err == LFS_ERR_NOSPC) {
goto dead; goto dead;
} }
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = 0;
sim_isdirs[k] = true;
break;
}
}
// mark any related sim files as zombied
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x) {
sim_files[k]->zombie = true;
}
}
} }
// check our simulation every power-of-2 ops // check our simulation every power-of-2 ops
@@ -1516,6 +1687,10 @@ code = '''
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(info.size == 0);
} else if (sim_isstickys[j]) {
assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else { } else {
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
@@ -1540,6 +1715,10 @@ code = '''
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(info.size == 0);
} else if (sim_isstickys[j]) {
assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else { } else {
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
@@ -1569,8 +1748,12 @@ code = '''
} }
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; if (sim_isstickys[j]) {
assert(memcmp(rbuf, wbuf, SIZE) == 0); lfsr_file_read(&lfs, &file, rbuf, SIZE) => 0;
} else {
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
}
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;
} }
} }
@@ -1596,6 +1779,8 @@ code = '''
// clean up sim/lfs // clean up sim/lfs
free(sim); free(sim);
free(sim_prngs); free(sim_prngs);
free(sim_isstickys);
free(sim_isdirs);
for (lfs_size_t j = 0; j < sim_file_count; j++) { for (lfs_size_t j = 0; j < sim_file_count; j++) {
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0; lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
+3194 -359
View File
File diff suppressed because it is too large Load Diff
+320 -142
View File
@@ -2838,11 +2838,12 @@ code = '''
// set up a simulation to compare against // set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t)); uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
bool *sim_isstickys = malloc(N*sizeof(bool));
lfs_size_t sim_size = 0; lfs_size_t sim_size = 0;
typedef struct sim_file { typedef struct sim_file {
lfs_size_t x; lfs_size_t x;
bool uncreat; bool sticky;
bool zombie; bool zombie;
uint32_t prng; uint32_t prng;
lfsr_file_t file; lfsr_file_t file;
@@ -2865,28 +2866,25 @@ code = '''
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// already exists? // already exists?
bool uncreat = true; bool exist = false;
uint32_t wprng = 0; uint32_t wprng = 0;
bool sticky = true;
for (lfs_size_t j = 0; j < sim_size; j++) { for (lfs_size_t j = 0; j < sim_size; j++) {
if (sim[j] == x) { if (sim[j] == x) {
uncreat = false; exist = true;
wprng = sim_prngs[j]; wprng = sim_prngs[j];
sticky = sim_isstickys[j];
break; break;
} }
} }
// choose a random seed if we don't exist // choose a random seed if we don't exist
if (uncreat) { if (!exist) {
wprng = TEST_PRNG(&prng); wprng = TEST_PRNG(&prng);
sticky = true;
} }
// open in our sim
lfs_size_t j = sim_file_count; lfs_size_t j = sim_file_count;
sim_files[j] = malloc(sizeof(sim_file_t)); sim_files[j] = malloc(sizeof(sim_file_t));
sim_files[j]->x = x;
sim_files[j]->uncreat = uncreat;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// open the actual file // open the actual file
char name[256]; char name[256];
@@ -2895,12 +2893,45 @@ code = '''
LFS_O_RDWR | LFS_O_CREAT) => 0; LFS_O_RDWR | LFS_O_CREAT) => 0;
// write some initial data if we don't exist // write some initial data if we don't exist
if (uncreat) { if (!exist || sticky) {
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE)
=> SIZE;
}
// open in our sim
sim_files[j]->x = x;
sim_files[j]->sticky = sticky;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
}
break;
} }
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
} }
// write/rewrite a file? // write/rewrite a file?
@@ -2914,26 +2945,27 @@ code = '''
// choose a random seed // choose a random seed
uint32_t wprng = TEST_PRNG(&prng); uint32_t wprng = TEST_PRNG(&prng);
// write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
lfsr_file_sync(&lfs, &sim_files[j]->file)
=> (!sim_files[j]->zombie) ? 0 : LFS_ERR_NOENT;
// update sim // update sim
sim_files[j]->prng = wprng; sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) { if (!sim_files[j]->zombie) {
// insert into our sim // update in our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (sim[k] == x) {
// already seen? // new prng
if (k < sim_size && sim[k] == x) { sim_prngs[k] = wprng;
// new prng // no longer sticky
sim_prngs[k] = wprng; sim_isstickys[k] = false;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
}
break; break;
} }
} }
@@ -2941,22 +2973,14 @@ code = '''
// update related sim files // update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) { for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) { if (sim_files[k]->x == x && !sim_files[k]->zombie) {
sim_files[k]->uncreat = false; // new prng
sim_files[k]->prng = wprng; sim_files[k]->prng = wprng;
// no longer sticky
sim_files[k]->sticky = false;
} }
} }
} }
// write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE];
for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
lfsr_file_sync(&lfs, &sim_files[j]->file)
=> (!sim_files[j]->zombie) ? 0 : LFS_ERR_NOENT;
// close a file? // close a file?
} else if (op == 2) { } else if (op == 2) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -2964,6 +2988,9 @@ code = '''
} }
// choose a random file handle // choose a random file handle
lfs_size_t j = TEST_PRNG(&prng) % sim_file_count; lfs_size_t j = TEST_PRNG(&prng) % sim_file_count;
lfs_size_t x = sim_files[j]->x;
bool sticky = sim_files[j]->sticky;
bool zombie = sim_files[j]->zombie;
// this doesn't really test anything, but if we don't close // this doesn't really test anything, but if we don't close
// files eventually everything will end up zombies // files eventually everything will end up zombies
@@ -2979,6 +3006,33 @@ code = '''
sim_files[j] = sim_files[sim_file_count-1]; sim_files[j] = sim_files[sim_file_count-1];
sim_file_count -= 1; sim_file_count -= 1;
// update our sim
if (sticky && !zombie) {
// orphaned?
bool orphan = true;
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
orphan = false;
}
}
// if we were never synced, delete from sim
if (orphan) {
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
memmove(&sim[k], &sim[k+1],
(sim_size-(k+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[k], &sim_prngs[k+1],
(sim_size-(k+1))*sizeof(uint32_t));
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
(sim_size-(k+1))*sizeof(bool));
sim_size -= 1;
break;
}
}
}
}
// remove a file? // remove a file?
} else if (op == 3) { } else if (op == 3) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -2988,11 +3042,18 @@ code = '''
lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t j = TEST_PRNG(&prng) % sim_size;
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
lfsr_remove(&lfs, name) => 0;
// delete from our sim // delete from our sim
memmove(&sim[j], &sim[j+1], memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
// mark any related sim files as zombied // mark any related sim files as zombied
@@ -3002,11 +3063,6 @@ code = '''
} }
} }
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
lfsr_remove(&lfs, name) => 0;
// rename a file? // rename a file?
} else if (op == 4) { } else if (op == 4) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -3018,6 +3074,14 @@ code = '''
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
lfs_size_t y = TEST_PRNG(&prng) % N; lfs_size_t y = TEST_PRNG(&prng) % N;
uint32_t wprng = sim_prngs[j]; uint32_t wprng = sim_prngs[j];
bool sticky = sim_isstickys[j];
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
lfsr_rename(&lfs, old_name, new_name) => 0;
// update our sim // update our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
@@ -3029,12 +3093,15 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
// update the prng // update the prng/sticky
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
// just renaming // just renaming
} else { } else {
// first delete // first delete
@@ -3042,6 +3109,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
@@ -3050,8 +3119,11 @@ code = '''
(sim_size-k)*sizeof(lfs_size_t)); (sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k], memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t)); (sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
sim[k] = y; sim[k] = y;
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
} }
break; break;
} }
@@ -3068,13 +3140,6 @@ code = '''
sim_files[k]->zombie = true; sim_files[k]->zombie = true;
} }
} }
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
lfsr_rename(&lfs, old_name, new_name) => 0;
} }
// gc! // gc!
@@ -3093,8 +3158,13 @@ code = '''
struct lfs_info info; struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0; lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_REG); if (sim_isstickys[j]) {
assert(info.size == SIZE); assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else {
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
} }
lfsr_dir_t dir; lfsr_dir_t dir;
@@ -3113,8 +3183,13 @@ code = '''
sprintf(name, "batman%03x", sim[j]); sprintf(name, "batman%03x", sim[j]);
lfsr_dir_read(&lfs, &dir, &info) => 0; lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_REG); if (sim_isstickys[j]) {
assert(info.size == SIZE); assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else {
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
} }
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0; lfsr_dir_close(&lfs, &dir) => 0;
@@ -3132,8 +3207,12 @@ code = '''
} }
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; if (sim_isstickys[j]) {
assert(memcmp(rbuf, wbuf, SIZE) == 0); lfsr_file_read(&lfs, &file, rbuf, SIZE) => 0;
} else {
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
}
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;
} }
@@ -3154,6 +3233,7 @@ code = '''
// clean up sim/lfs // clean up sim/lfs
free(sim); free(sim);
free(sim_prngs); free(sim_prngs);
free(sim_isstickys);
for (lfs_size_t j = 0; j < sim_file_count; j++) { for (lfs_size_t j = 0; j < sim_file_count; j++) {
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
free(sim_files[j]); free(sim_files[j]);
@@ -3203,12 +3283,13 @@ code = '''
// set up a simulation to compare against // set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t)); uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
bool *sim_isstickys = malloc(N*sizeof(bool));
bool *sim_isdirs = malloc(N*sizeof(bool)); bool *sim_isdirs = malloc(N*sizeof(bool));
lfs_size_t sim_size = 0; lfs_size_t sim_size = 0;
typedef struct sim_file { typedef struct sim_file {
lfs_size_t x; lfs_size_t x;
bool uncreat; bool sticky;
bool zombie; bool zombie;
uint32_t prng; uint32_t prng;
lfsr_file_t file; lfsr_file_t file;
@@ -3231,31 +3312,28 @@ code = '''
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// already exists? // already exists?
bool uncreat = true; bool exist = true;
uint32_t wprng = 0; uint32_t wprng = 0;
bool sticky = true;
for (lfs_size_t j = 0; j < sim_size; j++) { for (lfs_size_t j = 0; j < sim_size; j++) {
if (sim[j] == x) { if (sim[j] == x) {
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
goto nonsense; goto nonsense;
} }
uncreat = false; exist = true;
wprng = sim_prngs[j]; wprng = sim_prngs[j];
sticky = sim_isstickys[j];
break; break;
} }
} }
// choose a random seed if we don't exist // choose a random seed if we don't exist
if (uncreat) { if (!exist) {
wprng = TEST_PRNG(&prng); wprng = TEST_PRNG(&prng);
sticky = true;
} }
// open in our sim
lfs_size_t j = sim_file_count; lfs_size_t j = sim_file_count;
sim_files[j] = malloc(sizeof(sim_file_t)); sim_files[j] = malloc(sizeof(sim_file_t));
sim_files[j]->x = x;
sim_files[j]->uncreat = uncreat;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// open the actual file // open the actual file
char name[256]; char name[256];
@@ -3264,12 +3342,48 @@ code = '''
LFS_O_RDWR | LFS_O_CREAT) => 0; LFS_O_RDWR | LFS_O_CREAT) => 0;
// write some initial data if we don't exist // write some initial data if we don't exist
if (uncreat) { if (!exist || sticky) {
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE)
=> SIZE;
}
// open in our sim
sim_files[j]->x = x;
sim_files[j]->sticky = sticky;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
sim_isdirs[k] = false;
}
break;
} }
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
} }
// write/rewrite a file? // write/rewrite a file?
@@ -3283,29 +3397,27 @@ code = '''
// choose a random seed // choose a random seed
uint32_t wprng = TEST_PRNG(&prng); uint32_t wprng = TEST_PRNG(&prng);
// write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
lfsr_file_sync(&lfs, &sim_files[j]->file)
=> (!sim_files[j]->zombie) ? 0 : LFS_ERR_NOENT;
// update sim // update sim
sim_files[j]->prng = wprng; sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) { if (!sim_files[j]->zombie) {
// insert into our sim // update in our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (k >= sim_size || sim[k] >= x) {
// already seen? // new prng
if (k < sim_size && sim[k] == x) { sim_prngs[k] = wprng;
// new prng // no longer sticky
sim_prngs[k] = wprng; sim_isstickys[k] = false;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isdirs[k] = false;
}
break; break;
} }
} }
@@ -3313,22 +3425,14 @@ code = '''
// update related sim files // update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) { for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) { if (sim_files[k]->x == x && !sim_files[k]->zombie) {
sim_files[k]->uncreat = false; // new prng
sim_files[k]->prng = wprng; sim_files[k]->prng = wprng;
// no longer sticky
sim_files[k]->sticky = false;
} }
} }
} }
// write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE];
for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
lfsr_file_sync(&lfs, &sim_files[j]->file)
=> (!sim_files[j]->zombie) ? 0 : LFS_ERR_NOENT;
// close a file? // close a file?
} else if (op == 2) { } else if (op == 2) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -3336,6 +3440,9 @@ code = '''
} }
// choose a random file handle // choose a random file handle
lfs_size_t j = TEST_PRNG(&prng) % sim_file_count; lfs_size_t j = TEST_PRNG(&prng) % sim_file_count;
lfs_size_t x = sim_files[j]->x;
lfs_size_t sticky = sim_files[j]->sticky;
lfs_size_t zombie = sim_files[j]->zombie;
// this doesn't really test anything, but if we don't close // this doesn't really test anything, but if we don't close
// files eventually everything will end up zombies // files eventually everything will end up zombies
@@ -3351,6 +3458,35 @@ code = '''
sim_files[j] = sim_files[sim_file_count-1]; sim_files[j] = sim_files[sim_file_count-1];
sim_file_count -= 1; sim_file_count -= 1;
// update our sim
if (sticky && !zombie) {
// orphaned?
bool orphan = true;
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
orphan = false;
}
}
// if we were never synced, delete from sim
if (orphan) {
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
memmove(&sim[k], &sim[k+1],
(sim_size-(k+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[k], &sim_prngs[k+1],
(sim_size-(k+1))*sizeof(uint32_t));
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
(sim_size-(k+1))*sizeof(bool));
memmove(&sim_isdirs[k], &sim_isdirs[k+1],
(sim_size-(k+1))*sizeof(bool));
sim_size -= 1;
break;
}
}
}
}
// remove a file? // remove a file?
} else if (op == 3) { } else if (op == 3) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -3360,11 +3496,18 @@ code = '''
lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t j = TEST_PRNG(&prng) % sim_size;
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
lfsr_remove(&lfs, name) => 0;
// delete from our sim // delete from our sim
memmove(&sim[j], &sim[j+1], memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
@@ -3376,11 +3519,6 @@ code = '''
} }
} }
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
lfsr_remove(&lfs, name) => 0;
// rename a file? // rename a file?
} else if (op == 4) { } else if (op == 4) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -3392,31 +3530,51 @@ code = '''
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
lfs_size_t y = TEST_PRNG(&prng) % N; lfs_size_t y = TEST_PRNG(&prng) % N;
uint32_t wprng = sim_prngs[j]; uint32_t wprng = sim_prngs[j];
bool isdir = sim_isdirs[j]; bool sticky = sim_isstickys[j];
bool dir = sim_isdirs[j];
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= y) {
// renaming and replacing
if (k < sim_size && sim[k] == y && x != y) {
// type mismatch?
if (sim_isdirs[k] != dir) {
goto nonsense;
}
}
break;
}
}
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
lfsr_rename(&lfs, old_name, new_name) => 0;
// update our sim // update our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= y) { if (k >= sim_size || sim[k] >= y) {
// renaming and replacing // renaming and replacing
if (k < sim_size && sim[k] == y && x != y) { if (k < sim_size && sim[k] == y && x != y) {
// type mismatch?
if (sim_isdirs[k] != isdir) {
goto nonsense;
}
// delete the original entry // delete the original entry
memmove(&sim[j], &sim[j+1], memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
// update the prng // update the prng/sticky/dir
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
sim_isdirs[k] = dir;
// just renaming // just renaming
} else { } else {
// first delete // first delete
@@ -3424,6 +3582,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
if (k > j) { if (k > j) {
@@ -3434,11 +3594,14 @@ code = '''
(sim_size-k)*sizeof(lfs_size_t)); (sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k], memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t)); (sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k], memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool)); (sim_size-k)*sizeof(bool));
sim[k] = y; sim[k] = y;
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isdirs[k] = isdir; sim_isstickys[k] = sticky;
sim_isdirs[k] = dir;
} }
break; break;
} }
@@ -3456,52 +3619,52 @@ code = '''
} }
} }
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
lfsr_rename(&lfs, old_name, new_name) => 0;
// toss a directory into the mix // toss a directory into the mix
} else if (op == 5) { } else if (op == 5) {
// choose a pseudo-random number // choose a pseudo-random number
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// insert into our sim, use negative numbers for dirs
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (k >= sim_size || sim[k] >= x) {
// already seen? // already seen?
if (k < sim_size && sim[k] == x) { if (k < sim_size && sim[k] == x) {
goto nonsense; goto nonsense;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = 0;
sim_isdirs[k] = true;
} }
break; break;
} }
} }
// make the directory
char name[256];
sprintf(name, "batman%03x", x);
lfsr_mkdir(&lfs, name) => 0;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = 0;
sim_isdirs[k] = true;
break;
}
}
// mark any related sim files as zombied // mark any related sim files as zombied
for (lfs_size_t k = 0; k < sim_file_count; k++) { for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x) { if (sim_files[k]->x == x) {
sim_files[k]->zombie = true; sim_files[k]->zombie = true;
} }
} }
// make the directory
char name[256];
sprintf(name, "batman%03x", x);
lfsr_mkdir(&lfs, name) => 0;
} }
// gc! // gc!
@@ -3522,6 +3685,10 @@ code = '''
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(info.size == 0);
} else if (sim_isstickys[j]) {
assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else { } else {
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
@@ -3546,6 +3713,10 @@ code = '''
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(info.size == 0);
} else if (sim_isstickys[j]) {
assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else { } else {
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
@@ -3559,7 +3730,8 @@ code = '''
char name[256]; char name[256];
sprintf(name, "batman%03x", sim[j]); sprintf(name, "batman%03x", sim[j]);
lfsr_file_t file; lfsr_file_t file;
lfsr_file_open(&lfs, &file, name, LFS_O_RDONLY) => LFS_ERR_ISDIR; lfsr_file_open(&lfs, &file, name, LFS_O_RDONLY)
=> LFS_ERR_ISDIR;
} else { } else {
char name[256]; char name[256];
@@ -3574,8 +3746,12 @@ code = '''
} }
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; if (sim_isstickys[j]) {
assert(memcmp(rbuf, wbuf, SIZE) == 0); lfsr_file_read(&lfs, &file, rbuf, SIZE) => 0;
} else {
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
}
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;
} }
} }
@@ -3597,6 +3773,8 @@ code = '''
// clean up sim/lfs // clean up sim/lfs
free(sim); free(sim);
free(sim_prngs); free(sim_prngs);
free(sim_isstickys);
free(sim_isdirs);
for (lfs_size_t j = 0; j < sim_file_count; j++) { for (lfs_size_t j = 0; j < sim_file_count; j++) {
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
free(sim_files[j]); free(sim_files[j]);
+225 -66
View File
@@ -1273,11 +1273,12 @@ code = '''
// set up a simulation to compare against // set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t)); uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
bool *sim_isstickys = malloc(N*sizeof(bool));
lfs_size_t sim_size = 0; lfs_size_t sim_size = 0;
typedef struct sim_file { typedef struct sim_file {
lfs_size_t x; lfs_size_t x;
bool uncreat; bool sticky;
bool zombie; bool zombie;
uint32_t prng; uint32_t prng;
lfsr_file_t file; lfsr_file_t file;
@@ -1302,18 +1303,21 @@ code = '''
lfs_size_t x = TEST_PRNG(&prng_) % N; lfs_size_t x = TEST_PRNG(&prng_) % N;
// already exists? // already exists?
bool uncreat = true; bool exist = false;
uint32_t wprng = 0; uint32_t wprng = 0;
bool sticky = true;
for (lfs_size_t j = 0; j < sim_size; j++) { for (lfs_size_t j = 0; j < sim_size; j++) {
if (sim[j] == x) { if (sim[j] == x) {
uncreat = false; exist = true;
wprng = sim_prngs[j]; wprng = sim_prngs[j];
sticky = sim_isstickys[j];
break; break;
} }
} }
// choose a random seed if we don't exist // choose a random seed if we don't exist
if (uncreat) { if (!exist) {
wprng = TEST_PRNG(&prng_); wprng = TEST_PRNG(&prng_);
sticky = true;
} }
lfs_size_t j = sim_file_count; lfs_size_t j = sim_file_count;
@@ -1331,7 +1335,7 @@ code = '''
} }
// write some initial data if we don't exist // write some initial data if we don't exist
if (uncreat) { if (!exist || sticky) {
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng; uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
@@ -1349,11 +1353,35 @@ code = '''
// open in our sim // open in our sim
sim_files[j]->x = x; sim_files[j]->x = x;
sim_files[j]->uncreat = uncreat; sim_files[j]->sticky = sticky;
sim_files[j]->zombie = false; sim_files[j]->zombie = false;
sim_files[j]->prng = wprng; sim_files[j]->prng = wprng;
sim_file_count++; sim_file_count++;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
}
break;
}
}
// write/rewrite a file? // write/rewrite a file?
} else if (op == 1) { } else if (op == 1) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -1388,23 +1416,13 @@ code = '''
// update sim // update sim
sim_files[j]->prng = wprng; sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) { if (!sim_files[j]->zombie) {
// insert into our sim // update in our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (sim[k] == x) {
// already seen? // new prng
if (k < sim_size && sim[k] == x) { sim_prngs[k] = wprng;
// new prng // no longer sticky
sim_prngs[k] = wprng; sim_isstickys[k] = false;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
}
break; break;
} }
} }
@@ -1412,8 +1430,10 @@ code = '''
// update related sim files // update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) { for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) { if (sim_files[k]->x == x && !sim_files[k]->zombie) {
sim_files[k]->uncreat = false; // new prng
sim_files[k]->prng = wprng; sim_files[k]->prng = wprng;
// no longer sticky
sim_files[k]->sticky = false;
} }
} }
} }
@@ -1425,6 +1445,9 @@ code = '''
} }
// choose a random file handle // choose a random file handle
lfs_size_t j = TEST_PRNG(&prng_) % sim_file_count; lfs_size_t j = TEST_PRNG(&prng_) % sim_file_count;
lfs_size_t x = sim_files[j]->x;
bool sticky = sim_files[j]->sticky;
bool zombie = sim_files[j]->zombie;
// this doesn't really test anything, but if we don't close // this doesn't really test anything, but if we don't close
// files eventually everything will end up zombies // files eventually everything will end up zombies
@@ -1432,12 +1455,41 @@ code = '''
// close the file without affected disk // close the file without affected disk
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0; lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
// clobber closed files to try to catch lingering references
memset(&sim_files[j]->file, 0xcc, sizeof(lfsr_file_t));
// remove from list // remove from list
free(sim_files[j]); free(sim_files[j]);
sim_files[j] = sim_files[sim_file_count-1]; sim_files[j] = sim_files[sim_file_count-1];
sim_file_count -= 1; sim_file_count -= 1;
// update our sim
if (sticky && !zombie) {
// orphaned?
bool orphan = true;
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
orphan = false;
}
}
// if we were never synced, delete from sim
if (orphan) {
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
memmove(&sim[k], &sim[k+1],
(sim_size-(k+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[k], &sim_prngs[k+1],
(sim_size-(k+1))*sizeof(uint32_t));
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
(sim_size-(k+1))*sizeof(bool));
sim_size -= 1;
break;
}
}
}
}
// remove a file? // remove a file?
} else if (op == 3) { } else if (op == 3) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -1461,6 +1513,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
// mark any related sim files as zombied // mark any related sim files as zombied
@@ -1481,6 +1535,7 @@ code = '''
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
lfs_size_t y = TEST_PRNG(&prng_) % N; lfs_size_t y = TEST_PRNG(&prng_) % N;
uint32_t wprng = sim_prngs[j]; uint32_t wprng = sim_prngs[j];
bool sticky = sim_isstickys[j];
// rename this file // rename this file
char old_name[256]; char old_name[256];
@@ -1503,12 +1558,15 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
// update the prng // update the prng/sticky
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
// just renaming // just renaming
} else { } else {
// first delete // first delete
@@ -1516,6 +1574,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
@@ -1524,8 +1584,11 @@ code = '''
(sim_size-k)*sizeof(lfs_size_t)); (sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k], memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t)); (sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
sim[k] = y; sim[k] = y;
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
} }
break; break;
} }
@@ -1591,8 +1654,13 @@ code = '''
struct lfs_info info; struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0; lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_REG); if (sim_isstickys[j]) {
assert(info.size == SIZE); assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else {
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
} }
lfsr_dir_t dir; lfsr_dir_t dir;
@@ -1611,8 +1679,13 @@ code = '''
sprintf(name, "batman%03x", sim[j]); sprintf(name, "batman%03x", sim[j]);
lfsr_dir_read(&lfs, &dir, &info) => 0; lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_REG); if (sim_isstickys[j]) {
assert(info.size == SIZE); assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else {
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
} }
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0; lfsr_dir_close(&lfs, &dir) => 0;
@@ -1630,8 +1703,12 @@ code = '''
} }
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; if (sim_isstickys[j]) {
assert(memcmp(rbuf, wbuf, SIZE) == 0); lfsr_file_read(&lfs, &file, rbuf, SIZE) => 0;
} else {
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
}
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;
} }
@@ -1652,8 +1729,8 @@ code = '''
// clean up sim/lfs // clean up sim/lfs
free(sim); free(sim);
free(sim_prngs); free(sim_prngs);
free(sim_isstickys);
for (lfs_size_t j = 0; j < sim_file_count; j++) { for (lfs_size_t j = 0; j < sim_file_count; j++) {
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
free(sim_files[j]); free(sim_files[j]);
} }
@@ -1697,12 +1774,13 @@ code = '''
// set up a simulation to compare against // set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t)); uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
bool *sim_isstickys = malloc(N*sizeof(bool));
bool *sim_isdirs = malloc(N*sizeof(bool)); bool *sim_isdirs = malloc(N*sizeof(bool));
lfs_size_t sim_size = 0; lfs_size_t sim_size = 0;
typedef struct sim_file { typedef struct sim_file {
lfs_size_t x; lfs_size_t x;
bool uncreat; bool sticky;
bool zombie; bool zombie;
uint32_t prng; uint32_t prng;
lfsr_file_t file; lfsr_file_t file;
@@ -1727,21 +1805,24 @@ code = '''
lfs_size_t x = TEST_PRNG(&prng_) % N; lfs_size_t x = TEST_PRNG(&prng_) % N;
// already exists? // already exists?
bool uncreat = true; bool exist = true;
uint32_t wprng = 0; uint32_t wprng = 0;
bool sticky = true;
for (lfs_size_t j = 0; j < sim_size; j++) { for (lfs_size_t j = 0; j < sim_size; j++) {
if (sim[j] == x) { if (sim[j] == x) {
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
goto nonsense; goto nonsense;
} }
uncreat = false; exist = true;
wprng = sim_prngs[j]; wprng = sim_prngs[j];
sticky = sim_isstickys[j];
break; break;
} }
} }
// choose a random seed if we don't exist // choose a random seed if we don't exist
if (uncreat) { if (!exist) {
wprng = TEST_PRNG(&prng_); wprng = TEST_PRNG(&prng);
sticky = true;
} }
lfs_size_t j = sim_file_count; lfs_size_t j = sim_file_count;
@@ -1759,7 +1840,7 @@ code = '''
} }
// write some initial data if we don't exist // write some initial data if we don't exist
if (uncreat) { if (!exist || sticky) {
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng; uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
@@ -1777,11 +1858,38 @@ code = '''
// open in our sim // open in our sim
sim_files[j]->x = x; sim_files[j]->x = x;
sim_files[j]->uncreat = uncreat; sim_files[j]->sticky = sticky;
sim_files[j]->zombie = false; sim_files[j]->zombie = false;
sim_files[j]->prng = wprng; sim_files[j]->prng = wprng;
sim_file_count++; sim_file_count++;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
sim_isdirs[k] = false;
}
break;
}
}
// write/rewrite a file? // write/rewrite a file?
} else if (op == 1) { } else if (op == 1) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -1816,26 +1924,13 @@ code = '''
// update sim // update sim
sim_files[j]->prng = wprng; sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) { if (!sim_files[j]->zombie) {
// insert into our sim // update in our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (k >= sim_size || sim[k] >= x) {
// already seen? // new prng
if (k < sim_size && sim[k] == x) { sim_prngs[k] = wprng;
// new prng // no longer sticky
sim_prngs[k] = wprng; sim_isstickys[k] = false;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isdirs[k] = false;
}
break; break;
} }
} }
@@ -1843,8 +1938,10 @@ code = '''
// update related sim files // update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) { for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) { if (sim_files[k]->x == x && !sim_files[k]->zombie) {
sim_files[k]->uncreat = false; // new prng
sim_files[k]->prng = wprng; sim_files[k]->prng = wprng;
// no longer sticky
sim_files[k]->sticky = false;
} }
} }
} }
@@ -1856,6 +1953,9 @@ code = '''
} }
// choose a random file handle // choose a random file handle
lfs_size_t j = TEST_PRNG(&prng_) % sim_file_count; lfs_size_t j = TEST_PRNG(&prng_) % sim_file_count;
lfs_size_t x = sim_files[j]->x;
lfs_size_t sticky = sim_files[j]->sticky;
lfs_size_t zombie = sim_files[j]->zombie;
// this doesn't really test anything, but if we don't close // this doesn't really test anything, but if we don't close
// files eventually everything will end up zombies // files eventually everything will end up zombies
@@ -1863,12 +1963,43 @@ code = '''
// close the file without affected disk // close the file without affected disk
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0; lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
// clobber closed files to try to catch lingering references
memset(&sim_files[j]->file, 0xcc, sizeof(lfsr_file_t));
// remove from list // remove from list
free(sim_files[j]); free(sim_files[j]);
sim_files[j] = sim_files[sim_file_count-1]; sim_files[j] = sim_files[sim_file_count-1];
sim_file_count -= 1; sim_file_count -= 1;
// update our sim
if (sticky && !zombie) {
// orphaned?
bool orphan = true;
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
orphan = false;
}
}
// if we were never synced, delete from sim
if (orphan) {
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
memmove(&sim[k], &sim[k+1],
(sim_size-(k+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[k], &sim_prngs[k+1],
(sim_size-(k+1))*sizeof(uint32_t));
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
(sim_size-(k+1))*sizeof(bool));
memmove(&sim_isdirs[k], &sim_isdirs[k+1],
(sim_size-(k+1))*sizeof(bool));
sim_size -= 1;
break;
}
}
}
}
// remove a file? // remove a file?
} else if (op == 3) { } else if (op == 3) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -1892,6 +2023,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
@@ -1914,14 +2047,15 @@ code = '''
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
lfs_size_t y = TEST_PRNG(&prng_) % N; lfs_size_t y = TEST_PRNG(&prng_) % N;
uint32_t wprng = sim_prngs[j]; uint32_t wprng = sim_prngs[j];
bool isdir = sim_isdirs[j]; bool sticky = sim_isstickys[j];
bool dir = sim_isdirs[j];
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= y) { if (k >= sim_size || sim[k] >= y) {
// renaming and replacing // renaming and replacing
if (k < sim_size && sim[k] == y && x != y) { if (k < sim_size && sim[k] == y && x != y) {
// type mismatch? // type mismatch?
if (sim_isdirs[k] != isdir) { if (sim_isdirs[k] != dir) {
goto nonsense; goto nonsense;
} }
} }
@@ -1950,14 +2084,18 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
// update the prng // update the prng/sticky/dir
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
sim_isdirs[k] = dir;
// just renaming // just renaming
} else { } else {
// first delete // first delete
@@ -1965,6 +2103,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
if (k > j) { if (k > j) {
@@ -1975,11 +2115,14 @@ code = '''
(sim_size-k)*sizeof(lfs_size_t)); (sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k], memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t)); (sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k], memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool)); (sim_size-k)*sizeof(bool));
sim[k] = y; sim[k] = y;
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isdirs[k] = isdir; sim_isstickys[k] = sticky;
sim_isdirs[k] = dir;
} }
break; break;
} }
@@ -2021,7 +2164,7 @@ code = '''
goto grow; goto grow;
} }
// insert into our sim, use negative numbers for dirs // insert into our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (k >= sim_size || sim[k] >= x) {
// insert // insert
@@ -2029,6 +2172,8 @@ code = '''
(sim_size-k)*sizeof(lfs_size_t)); (sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k], memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t)); (sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k], memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool)); (sim_size-k)*sizeof(bool));
sim_size += 1; sim_size += 1;
@@ -2096,6 +2241,10 @@ code = '''
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(info.size == 0);
} else if (sim_isstickys[j]) {
assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else { } else {
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
@@ -2120,6 +2269,10 @@ code = '''
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(info.size == 0);
} else if (sim_isstickys[j]) {
assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else { } else {
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
@@ -2133,7 +2286,8 @@ code = '''
char name[256]; char name[256];
sprintf(name, "batman%03x", sim[j]); sprintf(name, "batman%03x", sim[j]);
lfsr_file_t file; lfsr_file_t file;
lfsr_file_open(&lfs, &file, name, LFS_O_RDONLY) => LFS_ERR_ISDIR; lfsr_file_open(&lfs, &file, name, LFS_O_RDONLY)
=> LFS_ERR_ISDIR;
} else { } else {
char name[256]; char name[256];
@@ -2148,8 +2302,12 @@ code = '''
} }
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; if (sim_isstickys[j]) {
assert(memcmp(rbuf, wbuf, SIZE) == 0); lfsr_file_read(&lfs, &file, rbuf, SIZE) => 0;
} else {
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
}
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;
} }
} }
@@ -2171,8 +2329,9 @@ code = '''
// clean up sim/lfs // clean up sim/lfs
free(sim); free(sim);
free(sim_prngs); free(sim_prngs);
free(sim_isstickys);
free(sim_isdirs);
for (lfs_size_t j = 0; j < sim_file_count; j++) { for (lfs_size_t j = 0; j < sim_file_count; j++) {
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
free(sim_files[j]); free(sim_files[j]);
} }
+324 -142
View File
@@ -552,11 +552,12 @@ code = '''
// set up a simulation to compare against // set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t)); uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
bool *sim_isstickys = malloc(N*sizeof(bool));
lfs_size_t sim_size = 0; lfs_size_t sim_size = 0;
typedef struct sim_file { typedef struct sim_file {
lfs_size_t x; lfs_size_t x;
bool uncreat; bool sticky;
bool zombie; bool zombie;
uint32_t prng; uint32_t prng;
lfsr_file_t file; lfsr_file_t file;
@@ -579,28 +580,25 @@ code = '''
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// already exists? // already exists?
bool uncreat = true; bool exist = false;
uint32_t wprng = 0; uint32_t wprng = 0;
bool sticky = true;
for (lfs_size_t j = 0; j < sim_size; j++) { for (lfs_size_t j = 0; j < sim_size; j++) {
if (sim[j] == x) { if (sim[j] == x) {
uncreat = false; exist = true;
wprng = sim_prngs[j]; wprng = sim_prngs[j];
sticky = sim_isstickys[j];
break; break;
} }
} }
// choose a random seed if we don't exist // choose a random seed if we don't exist
if (uncreat) { if (!exist) {
wprng = TEST_PRNG(&prng); wprng = TEST_PRNG(&prng);
sticky = true;
} }
// open in our sim
lfs_size_t j = sim_file_count; lfs_size_t j = sim_file_count;
sim_files[j] = malloc(sizeof(sim_file_t)); sim_files[j] = malloc(sizeof(sim_file_t));
sim_files[j]->x = x;
sim_files[j]->uncreat = uncreat;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// open the actual file // open the actual file
char name[256]; char name[256];
@@ -609,12 +607,45 @@ code = '''
LFS_O_RDWR | LFS_O_CREAT) => 0; LFS_O_RDWR | LFS_O_CREAT) => 0;
// write some initial data if we don't exist // write some initial data if we don't exist
if (uncreat) { if (!exist || sticky) {
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE)
=> SIZE;
}
// open in our sim
sim_files[j]->x = x;
sim_files[j]->sticky = sticky;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
}
break;
} }
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
} }
// write/rewrite a file? // write/rewrite a file?
@@ -628,26 +659,27 @@ code = '''
// choose a random seed // choose a random seed
uint32_t wprng = TEST_PRNG(&prng); uint32_t wprng = TEST_PRNG(&prng);
// write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
lfsr_file_sync(&lfs, &sim_files[j]->file)
=> (!sim_files[j]->zombie) ? 0 : LFS_ERR_NOENT;
// update sim // update sim
sim_files[j]->prng = wprng; sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) { if (!sim_files[j]->zombie) {
// insert into our sim // update in our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (sim[k] == x) {
// already seen? // new prng
if (k < sim_size && sim[k] == x) { sim_prngs[k] = wprng;
// new prng // no longer sticky
sim_prngs[k] = wprng; sim_isstickys[k] = false;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
}
break; break;
} }
} }
@@ -655,22 +687,14 @@ code = '''
// update related sim files // update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) { for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) { if (sim_files[k]->x == x && !sim_files[k]->zombie) {
sim_files[k]->uncreat = false; // new prng
sim_files[k]->prng = wprng; sim_files[k]->prng = wprng;
// no longer sticky
sim_files[k]->sticky = false;
} }
} }
} }
// write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE];
for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
lfsr_file_sync(&lfs, &sim_files[j]->file)
=> (!sim_files[j]->zombie) ? 0 : LFS_ERR_NOENT;
// close a file? // close a file?
} else if (op == 2) { } else if (op == 2) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -678,6 +702,9 @@ code = '''
} }
// choose a random file handle // choose a random file handle
lfs_size_t j = TEST_PRNG(&prng) % sim_file_count; lfs_size_t j = TEST_PRNG(&prng) % sim_file_count;
lfs_size_t x = sim_files[j]->x;
bool sticky = sim_files[j]->sticky;
bool zombie = sim_files[j]->zombie;
// this doesn't really test anything, but if we don't close // this doesn't really test anything, but if we don't close
// files eventually everything will end up zombies // files eventually everything will end up zombies
@@ -685,12 +712,41 @@ code = '''
// close the file without affected disk // close the file without affected disk
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0; lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
// clobber closed files to try to catch lingering references
memset(&sim_files[j]->file, 0xcc, sizeof(lfsr_file_t));
// remove from list // remove from list
free(sim_files[j]); free(sim_files[j]);
sim_files[j] = sim_files[sim_file_count-1]; sim_files[j] = sim_files[sim_file_count-1];
sim_file_count -= 1; sim_file_count -= 1;
// update our sim
if (sticky && !zombie) {
// orphaned?
bool orphan = true;
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
orphan = false;
}
}
// if we were never synced, delete from sim
if (orphan) {
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
memmove(&sim[k], &sim[k+1],
(sim_size-(k+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[k], &sim_prngs[k+1],
(sim_size-(k+1))*sizeof(uint32_t));
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
(sim_size-(k+1))*sizeof(bool));
sim_size -= 1;
break;
}
}
}
}
// remove a file? // remove a file?
} else if (op == 3) { } else if (op == 3) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -700,11 +756,18 @@ code = '''
lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t j = TEST_PRNG(&prng) % sim_size;
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
lfsr_remove(&lfs, name) => 0;
// delete from our sim // delete from our sim
memmove(&sim[j], &sim[j+1], memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
// mark any related sim files as zombied // mark any related sim files as zombied
@@ -714,11 +777,6 @@ code = '''
} }
} }
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
lfsr_remove(&lfs, name) => 0;
// rename a file? // rename a file?
} else if (op == 4) { } else if (op == 4) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -730,6 +788,14 @@ code = '''
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
lfs_size_t y = TEST_PRNG(&prng) % N; lfs_size_t y = TEST_PRNG(&prng) % N;
uint32_t wprng = sim_prngs[j]; uint32_t wprng = sim_prngs[j];
bool sticky = sim_isstickys[j];
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
lfsr_rename(&lfs, old_name, new_name) => 0;
// update our sim // update our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
@@ -741,12 +807,15 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
// update the prng // update the prng/sticky
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
// just renaming // just renaming
} else { } else {
// first delete // first delete
@@ -754,6 +823,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
@@ -762,8 +833,11 @@ code = '''
(sim_size-k)*sizeof(lfs_size_t)); (sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k], memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t)); (sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
sim[k] = y; sim[k] = y;
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
} }
break; break;
} }
@@ -780,13 +854,6 @@ code = '''
sim_files[k]->zombie = true; sim_files[k]->zombie = true;
} }
} }
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
lfsr_rename(&lfs, old_name, new_name) => 0;
} }
} }
@@ -797,8 +864,13 @@ code = '''
struct lfs_info info; struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0; lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_REG); if (sim_isstickys[j]) {
assert(info.size == SIZE); assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else {
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
} }
lfsr_dir_t dir; lfsr_dir_t dir;
@@ -817,8 +889,13 @@ code = '''
sprintf(name, "batman%03x", sim[j]); sprintf(name, "batman%03x", sim[j]);
lfsr_dir_read(&lfs, &dir, &info) => 0; lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_REG); if (sim_isstickys[j]) {
assert(info.size == SIZE); assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else {
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
} }
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0; lfsr_dir_close(&lfs, &dir) => 0;
@@ -836,8 +913,12 @@ code = '''
} }
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; if (sim_isstickys[j]) {
assert(memcmp(rbuf, wbuf, SIZE) == 0); lfsr_file_read(&lfs, &file, rbuf, SIZE) => 0;
} else {
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
}
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;
} }
@@ -858,6 +939,7 @@ code = '''
// clean up sim/lfs // clean up sim/lfs
free(sim); free(sim);
free(sim_prngs); free(sim_prngs);
free(sim_isstickys);
for (lfs_size_t j = 0; j < sim_file_count; j++) { for (lfs_size_t j = 0; j < sim_file_count; j++) {
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
free(sim_files[j]); free(sim_files[j]);
@@ -892,12 +974,13 @@ code = '''
// set up a simulation to compare against // set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t)); uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
bool *sim_isstickys = malloc(N*sizeof(bool));
bool *sim_isdirs = malloc(N*sizeof(bool)); bool *sim_isdirs = malloc(N*sizeof(bool));
lfs_size_t sim_size = 0; lfs_size_t sim_size = 0;
typedef struct sim_file { typedef struct sim_file {
lfs_size_t x; lfs_size_t x;
bool uncreat; bool sticky;
bool zombie; bool zombie;
uint32_t prng; uint32_t prng;
lfsr_file_t file; lfsr_file_t file;
@@ -920,31 +1003,28 @@ code = '''
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// already exists? // already exists?
bool uncreat = true; bool exist = true;
uint32_t wprng = 0; uint32_t wprng = 0;
bool sticky = true;
for (lfs_size_t j = 0; j < sim_size; j++) { for (lfs_size_t j = 0; j < sim_size; j++) {
if (sim[j] == x) { if (sim[j] == x) {
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
goto nonsense; goto nonsense;
} }
uncreat = false; exist = true;
wprng = sim_prngs[j]; wprng = sim_prngs[j];
sticky = sim_isstickys[j];
break; break;
} }
} }
// choose a random seed if we don't exist // choose a random seed if we don't exist
if (uncreat) { if (!exist) {
wprng = TEST_PRNG(&prng); wprng = TEST_PRNG(&prng);
sticky = true;
} }
// open in our sim
lfs_size_t j = sim_file_count; lfs_size_t j = sim_file_count;
sim_files[j] = malloc(sizeof(sim_file_t)); sim_files[j] = malloc(sizeof(sim_file_t));
sim_files[j]->x = x;
sim_files[j]->uncreat = uncreat;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// open the actual file // open the actual file
char name[256]; char name[256];
@@ -953,12 +1033,48 @@ code = '''
LFS_O_RDWR | LFS_O_CREAT) => 0; LFS_O_RDWR | LFS_O_CREAT) => 0;
// write some initial data if we don't exist // write some initial data if we don't exist
if (uncreat) { if (!exist || sticky) {
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE)
=> SIZE;
}
// open in our sim
sim_files[j]->x = x;
sim_files[j]->sticky = sticky;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
sim_isdirs[k] = false;
}
break;
} }
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
} }
// write/rewrite a file? // write/rewrite a file?
@@ -972,29 +1088,27 @@ code = '''
// choose a random seed // choose a random seed
uint32_t wprng = TEST_PRNG(&prng); uint32_t wprng = TEST_PRNG(&prng);
// write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
lfsr_file_sync(&lfs, &sim_files[j]->file)
=> (!sim_files[j]->zombie) ? 0 : LFS_ERR_NOENT;
// update sim // update sim
sim_files[j]->prng = wprng; sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) { if (!sim_files[j]->zombie) {
// insert into our sim // update in our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (k >= sim_size || sim[k] >= x) {
// already seen? // new prng
if (k < sim_size && sim[k] == x) { sim_prngs[k] = wprng;
// new prng // no longer sticky
sim_prngs[k] = wprng; sim_isstickys[k] = false;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isdirs[k] = false;
}
break; break;
} }
} }
@@ -1002,22 +1116,14 @@ code = '''
// update related sim files // update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) { for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) { if (sim_files[k]->x == x && !sim_files[k]->zombie) {
sim_files[k]->uncreat = false; // new prng
sim_files[k]->prng = wprng; sim_files[k]->prng = wprng;
// no longer sticky
sim_files[k]->sticky = false;
} }
} }
} }
// write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE];
for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
lfsr_file_sync(&lfs, &sim_files[j]->file)
=> (!sim_files[j]->zombie) ? 0 : LFS_ERR_NOENT;
// close a file? // close a file?
} else if (op == 2) { } else if (op == 2) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -1025,6 +1131,9 @@ code = '''
} }
// choose a random file handle // choose a random file handle
lfs_size_t j = TEST_PRNG(&prng) % sim_file_count; lfs_size_t j = TEST_PRNG(&prng) % sim_file_count;
lfs_size_t x = sim_files[j]->x;
lfs_size_t sticky = sim_files[j]->sticky;
lfs_size_t zombie = sim_files[j]->zombie;
// this doesn't really test anything, but if we don't close // this doesn't really test anything, but if we don't close
// files eventually everything will end up zombies // files eventually everything will end up zombies
@@ -1032,12 +1141,43 @@ code = '''
// close the file without affected disk // close the file without affected disk
lfsr_file_desync(&lfs, &sim_files[j]->file) => 0; lfsr_file_desync(&lfs, &sim_files[j]->file) => 0;
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
// clobber closed files to try to catch lingering references
memset(&sim_files[j]->file, 0xcc, sizeof(lfsr_file_t));
// remove from list // remove from list
free(sim_files[j]); free(sim_files[j]);
sim_files[j] = sim_files[sim_file_count-1]; sim_files[j] = sim_files[sim_file_count-1];
sim_file_count -= 1; sim_file_count -= 1;
// update our sim
if (sticky && !zombie) {
// orphaned?
bool orphan = true;
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
orphan = false;
}
}
// if we were never synced, delete from sim
if (orphan) {
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
memmove(&sim[k], &sim[k+1],
(sim_size-(k+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[k], &sim_prngs[k+1],
(sim_size-(k+1))*sizeof(uint32_t));
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
(sim_size-(k+1))*sizeof(bool));
memmove(&sim_isdirs[k], &sim_isdirs[k+1],
(sim_size-(k+1))*sizeof(bool));
sim_size -= 1;
break;
}
}
}
}
// remove a file? // remove a file?
} else if (op == 3) { } else if (op == 3) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -1047,11 +1187,18 @@ code = '''
lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t j = TEST_PRNG(&prng) % sim_size;
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
lfsr_remove(&lfs, name) => 0;
// delete from our sim // delete from our sim
memmove(&sim[j], &sim[j+1], memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
@@ -1063,11 +1210,6 @@ code = '''
} }
} }
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
lfsr_remove(&lfs, name) => 0;
// rename a file? // rename a file?
} else if (op == 4) { } else if (op == 4) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -1079,31 +1221,51 @@ code = '''
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
lfs_size_t y = TEST_PRNG(&prng) % N; lfs_size_t y = TEST_PRNG(&prng) % N;
uint32_t wprng = sim_prngs[j]; uint32_t wprng = sim_prngs[j];
bool isdir = sim_isdirs[j]; bool sticky = sim_isstickys[j];
bool dir = sim_isdirs[j];
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= y) {
// renaming and replacing
if (k < sim_size && sim[k] == y && x != y) {
// type mismatch?
if (sim_isdirs[k] != dir) {
goto nonsense;
}
}
break;
}
}
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
lfsr_rename(&lfs, old_name, new_name) => 0;
// update our sim // update our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= y) { if (k >= sim_size || sim[k] >= y) {
// renaming and replacing // renaming and replacing
if (k < sim_size && sim[k] == y && x != y) { if (k < sim_size && sim[k] == y && x != y) {
// type mismatch?
if (sim_isdirs[k] != isdir) {
goto nonsense;
}
// delete the original entry // delete the original entry
memmove(&sim[j], &sim[j+1], memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
// update the prng // update the prng/sticky/dir
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
sim_isdirs[k] = dir;
// just renaming // just renaming
} else { } else {
// first delete // first delete
@@ -1111,6 +1273,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
if (k > j) { if (k > j) {
@@ -1121,11 +1285,14 @@ code = '''
(sim_size-k)*sizeof(lfs_size_t)); (sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k], memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t)); (sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k], memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool)); (sim_size-k)*sizeof(bool));
sim[k] = y; sim[k] = y;
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isdirs[k] = isdir; sim_isstickys[k] = sticky;
sim_isdirs[k] = dir;
} }
break; break;
} }
@@ -1143,52 +1310,52 @@ code = '''
} }
} }
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
lfsr_rename(&lfs, old_name, new_name) => 0;
// toss a directory into the mix // toss a directory into the mix
} else if (op == 5) { } else if (op == 5) {
// choose a pseudo-random number // choose a pseudo-random number
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// insert into our sim, use negative numbers for dirs
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (k >= sim_size || sim[k] >= x) {
// already seen? // already seen?
if (k < sim_size && sim[k] == x) { if (k < sim_size && sim[k] == x) {
goto nonsense; goto nonsense;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = 0;
sim_isdirs[k] = true;
} }
break; break;
} }
} }
// make the directory
char name[256];
sprintf(name, "batman%03x", x);
lfsr_mkdir(&lfs, name) => 0;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = 0;
sim_isdirs[k] = true;
break;
}
}
// mark any related sim files as zombied // mark any related sim files as zombied
for (lfs_size_t k = 0; k < sim_file_count; k++) { for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x) { if (sim_files[k]->x == x) {
sim_files[k]->zombie = true; sim_files[k]->zombie = true;
} }
} }
// make the directory
char name[256];
sprintf(name, "batman%03x", x);
lfsr_mkdir(&lfs, name) => 0;
} }
} }
@@ -1201,6 +1368,10 @@ code = '''
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(info.size == 0);
} else if (sim_isstickys[j]) {
assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else { } else {
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
@@ -1225,6 +1396,10 @@ code = '''
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(info.size == 0);
} else if (sim_isstickys[j]) {
assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else { } else {
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
@@ -1238,7 +1413,8 @@ code = '''
char name[256]; char name[256];
sprintf(name, "batman%03x", sim[j]); sprintf(name, "batman%03x", sim[j]);
lfsr_file_t file; lfsr_file_t file;
lfsr_file_open(&lfs, &file, name, LFS_O_RDONLY) => LFS_ERR_ISDIR; lfsr_file_open(&lfs, &file, name, LFS_O_RDONLY)
=> LFS_ERR_ISDIR;
} else { } else {
char name[256]; char name[256];
@@ -1253,8 +1429,12 @@ code = '''
} }
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; if (sim_isstickys[j]) {
assert(memcmp(rbuf, wbuf, SIZE) == 0); lfsr_file_read(&lfs, &file, rbuf, SIZE) => 0;
} else {
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
}
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;
} }
} }
@@ -1276,6 +1456,8 @@ code = '''
// clean up sim/lfs // clean up sim/lfs
free(sim); free(sim);
free(sim_prngs); free(sim_prngs);
free(sim_isstickys);
free(sim_isdirs);
for (lfs_size_t j = 0; j < sim_file_count; j++) { for (lfs_size_t j = 0; j < sim_file_count; j++) {
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
free(sim_files[j]); free(sim_files[j]);
+320 -142
View File
@@ -8505,11 +8505,12 @@ code = '''
// set up a simulation to compare against // set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t)); uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
bool *sim_isstickys = malloc(N*sizeof(bool));
lfs_size_t sim_size = 0; lfs_size_t sim_size = 0;
typedef struct sim_file { typedef struct sim_file {
lfs_size_t x; lfs_size_t x;
bool uncreat; bool sticky;
bool zombie; bool zombie;
uint32_t prng; uint32_t prng;
lfsr_file_t file; lfsr_file_t file;
@@ -8541,28 +8542,25 @@ code = '''
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// already exists? // already exists?
bool uncreat = true; bool exist = false;
uint32_t wprng = 0; uint32_t wprng = 0;
bool sticky = true;
for (lfs_size_t j = 0; j < sim_size; j++) { for (lfs_size_t j = 0; j < sim_size; j++) {
if (sim[j] == x) { if (sim[j] == x) {
uncreat = false; exist = true;
wprng = sim_prngs[j]; wprng = sim_prngs[j];
sticky = sim_isstickys[j];
break; break;
} }
} }
// choose a random seed if we don't exist // choose a random seed if we don't exist
if (uncreat) { if (!exist) {
wprng = TEST_PRNG(&prng); wprng = TEST_PRNG(&prng);
sticky = true;
} }
// open in our sim
lfs_size_t j = sim_file_count; lfs_size_t j = sim_file_count;
sim_files[j] = malloc(sizeof(sim_file_t)); sim_files[j] = malloc(sizeof(sim_file_t));
sim_files[j]->x = x;
sim_files[j]->uncreat = uncreat;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// open the actual file // open the actual file
char name[256]; char name[256];
@@ -8571,12 +8569,45 @@ code = '''
LFS_O_RDWR | LFS_O_CREAT) => 0; LFS_O_RDWR | LFS_O_CREAT) => 0;
// write some initial data if we don't exist // write some initial data if we don't exist
if (uncreat) { if (!exist || sticky) {
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE)
=> SIZE;
}
// open in our sim
sim_files[j]->x = x;
sim_files[j]->sticky = sticky;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
}
break;
} }
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
} }
// write/rewrite a file? // write/rewrite a file?
@@ -8590,26 +8621,27 @@ code = '''
// choose a random seed // choose a random seed
uint32_t wprng = TEST_PRNG(&prng); uint32_t wprng = TEST_PRNG(&prng);
// write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
lfsr_file_sync(&lfs, &sim_files[j]->file)
=> (!sim_files[j]->zombie) ? 0 : LFS_ERR_NOENT;
// update sim // update sim
sim_files[j]->prng = wprng; sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) { if (!sim_files[j]->zombie) {
// insert into our sim // update in our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (sim[k] == x) {
// already seen? // new prng
if (k < sim_size && sim[k] == x) { sim_prngs[k] = wprng;
// new prng // no longer sticky
sim_prngs[k] = wprng; sim_isstickys[k] = false;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
}
break; break;
} }
} }
@@ -8617,22 +8649,14 @@ code = '''
// update related sim files // update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) { for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) { if (sim_files[k]->x == x && !sim_files[k]->zombie) {
sim_files[k]->uncreat = false; // new prng
sim_files[k]->prng = wprng; sim_files[k]->prng = wprng;
// no longer sticky
sim_files[k]->sticky = false;
} }
} }
} }
// write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE];
for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
lfsr_file_sync(&lfs, &sim_files[j]->file)
=> (!sim_files[j]->zombie) ? 0 : LFS_ERR_NOENT;
// close a file? // close a file?
} else if (op == 2) { } else if (op == 2) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -8640,6 +8664,9 @@ code = '''
} }
// choose a random file handle // choose a random file handle
lfs_size_t j = TEST_PRNG(&prng) % sim_file_count; lfs_size_t j = TEST_PRNG(&prng) % sim_file_count;
lfs_size_t x = sim_files[j]->x;
bool sticky = sim_files[j]->sticky;
bool zombie = sim_files[j]->zombie;
// this doesn't really test anything, but if we don't close // this doesn't really test anything, but if we don't close
// files eventually everything will end up zombies // files eventually everything will end up zombies
@@ -8655,6 +8682,33 @@ code = '''
sim_files[j] = sim_files[sim_file_count-1]; sim_files[j] = sim_files[sim_file_count-1];
sim_file_count -= 1; sim_file_count -= 1;
// update our sim
if (sticky && !zombie) {
// orphaned?
bool orphan = true;
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
orphan = false;
}
}
// if we were never synced, delete from sim
if (orphan) {
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
memmove(&sim[k], &sim[k+1],
(sim_size-(k+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[k], &sim_prngs[k+1],
(sim_size-(k+1))*sizeof(uint32_t));
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
(sim_size-(k+1))*sizeof(bool));
sim_size -= 1;
break;
}
}
}
}
// remove a file? // remove a file?
} else if (op == 3) { } else if (op == 3) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -8664,11 +8718,18 @@ code = '''
lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t j = TEST_PRNG(&prng) % sim_size;
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
lfsr_remove(&lfs, name) => 0;
// delete from our sim // delete from our sim
memmove(&sim[j], &sim[j+1], memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
// mark any related sim files as zombied // mark any related sim files as zombied
@@ -8678,11 +8739,6 @@ code = '''
} }
} }
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
lfsr_remove(&lfs, name) => 0;
// rename a file? // rename a file?
} else if (op == 4) { } else if (op == 4) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -8694,6 +8750,14 @@ code = '''
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
lfs_size_t y = TEST_PRNG(&prng) % N; lfs_size_t y = TEST_PRNG(&prng) % N;
uint32_t wprng = sim_prngs[j]; uint32_t wprng = sim_prngs[j];
bool sticky = sim_isstickys[j];
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
lfsr_rename(&lfs, old_name, new_name) => 0;
// update our sim // update our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
@@ -8705,12 +8769,15 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
// update the prng // update the prng/sticky
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
// just renaming // just renaming
} else { } else {
// first delete // first delete
@@ -8718,6 +8785,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
@@ -8726,8 +8795,11 @@ code = '''
(sim_size-k)*sizeof(lfs_size_t)); (sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k], memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t)); (sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
sim[k] = y; sim[k] = y;
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
} }
break; break;
} }
@@ -8744,13 +8816,6 @@ code = '''
sim_files[k]->zombie = true; sim_files[k]->zombie = true;
} }
} }
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
lfsr_rename(&lfs, old_name, new_name) => 0;
} }
// step the traversal // step the traversal
@@ -8774,8 +8839,13 @@ code = '''
struct lfs_info info; struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0; lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_REG); if (sim_isstickys[j]) {
assert(info.size == SIZE); assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else {
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
} }
lfsr_dir_t dir; lfsr_dir_t dir;
@@ -8794,8 +8864,13 @@ code = '''
sprintf(name, "batman%03x", sim[j]); sprintf(name, "batman%03x", sim[j]);
lfsr_dir_read(&lfs, &dir, &info) => 0; lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_REG); if (sim_isstickys[j]) {
assert(info.size == SIZE); assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else {
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
}
} }
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0; lfsr_dir_close(&lfs, &dir) => 0;
@@ -8813,8 +8888,12 @@ code = '''
} }
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; if (sim_isstickys[j]) {
assert(memcmp(rbuf, wbuf, SIZE) == 0); lfsr_file_read(&lfs, &file, rbuf, SIZE) => 0;
} else {
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
}
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;
} }
@@ -8835,6 +8914,7 @@ code = '''
// clean up sim/lfs // clean up sim/lfs
free(sim); free(sim);
free(sim_prngs); free(sim_prngs);
free(sim_isstickys);
for (lfs_size_t j = 0; j < sim_file_count; j++) { for (lfs_size_t j = 0; j < sim_file_count; j++) {
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
free(sim_files[j]); free(sim_files[j]);
@@ -8876,12 +8956,13 @@ code = '''
// set up a simulation to compare against // set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t)); lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t)); uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
bool *sim_isstickys = malloc(N*sizeof(bool));
bool *sim_isdirs = malloc(N*sizeof(bool)); bool *sim_isdirs = malloc(N*sizeof(bool));
lfs_size_t sim_size = 0; lfs_size_t sim_size = 0;
typedef struct sim_file { typedef struct sim_file {
lfs_size_t x; lfs_size_t x;
bool uncreat; bool sticky;
bool zombie; bool zombie;
uint32_t prng; uint32_t prng;
lfsr_file_t file; lfsr_file_t file;
@@ -8913,31 +8994,28 @@ code = '''
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// already exists? // already exists?
bool uncreat = true; bool exist = true;
uint32_t wprng = 0; uint32_t wprng = 0;
bool sticky = true;
for (lfs_size_t j = 0; j < sim_size; j++) { for (lfs_size_t j = 0; j < sim_size; j++) {
if (sim[j] == x) { if (sim[j] == x) {
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
goto nonsense; goto nonsense;
} }
uncreat = false; exist = true;
wprng = sim_prngs[j]; wprng = sim_prngs[j];
sticky = sim_isstickys[j];
break; break;
} }
} }
// choose a random seed if we don't exist // choose a random seed if we don't exist
if (uncreat) { if (!exist) {
wprng = TEST_PRNG(&prng); wprng = TEST_PRNG(&prng);
sticky = true;
} }
// open in our sim
lfs_size_t j = sim_file_count; lfs_size_t j = sim_file_count;
sim_files[j] = malloc(sizeof(sim_file_t)); sim_files[j] = malloc(sizeof(sim_file_t));
sim_files[j]->x = x;
sim_files[j]->uncreat = uncreat;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// open the actual file // open the actual file
char name[256]; char name[256];
@@ -8946,12 +9024,48 @@ code = '''
LFS_O_RDWR | LFS_O_CREAT) => 0; LFS_O_RDWR | LFS_O_CREAT) => 0;
// write some initial data if we don't exist // write some initial data if we don't exist
if (uncreat) { if (!exist || sticky) {
uint8_t wbuf[SIZE]; uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) { for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26); wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE)
=> SIZE;
}
// open in our sim
sim_files[j]->x = x;
sim_files[j]->sticky = sticky;
sim_files[j]->zombie = false;
sim_files[j]->prng = wprng;
sim_file_count++;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// already seen?
if (k < sim_size && sim[k] == x) {
// new prng
sim_prngs[k] = wprng;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
sim_isdirs[k] = false;
}
break;
} }
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
} }
// write/rewrite a file? // write/rewrite a file?
@@ -8965,29 +9079,27 @@ code = '''
// choose a random seed // choose a random seed
uint32_t wprng = TEST_PRNG(&prng); uint32_t wprng = TEST_PRNG(&prng);
// write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE];
uint32_t wprng_ = wprng;
for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
lfsr_file_sync(&lfs, &sim_files[j]->file)
=> (!sim_files[j]->zombie) ? 0 : LFS_ERR_NOENT;
// update sim // update sim
sim_files[j]->prng = wprng; sim_files[j]->prng = wprng;
if (!sim_files[j]->zombie) { if (!sim_files[j]->zombie) {
// insert into our sim // update in our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (k >= sim_size || sim[k] >= x) {
// already seen? // new prng
if (k < sim_size && sim[k] == x) { sim_prngs[k] = wprng;
// new prng // no longer sticky
sim_prngs[k] = wprng; sim_isstickys[k] = false;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = wprng;
sim_isdirs[k] = false;
}
break; break;
} }
} }
@@ -8995,22 +9107,14 @@ code = '''
// update related sim files // update related sim files
for (lfs_size_t k = 0; k < sim_file_count; k++) { for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) { if (sim_files[k]->x == x && !sim_files[k]->zombie) {
sim_files[k]->uncreat = false; // new prng
sim_files[k]->prng = wprng; sim_files[k]->prng = wprng;
// no longer sticky
sim_files[k]->sticky = false;
} }
} }
} }
// write to the file
lfsr_file_rewind(&lfs, &sim_files[j]->file) => 0;
uint8_t wbuf[SIZE];
for (lfs_size_t k = 0; k < SIZE; k++) {
wbuf[k] = 'a' + (TEST_PRNG(&wprng) % 26);
}
lfsr_file_write(&lfs, &sim_files[j]->file, wbuf, SIZE) => SIZE;
lfsr_file_sync(&lfs, &sim_files[j]->file)
=> (!sim_files[j]->zombie) ? 0 : LFS_ERR_NOENT;
// close a file? // close a file?
} else if (op == 2) { } else if (op == 2) {
if (sim_file_count == 0) { if (sim_file_count == 0) {
@@ -9018,6 +9122,9 @@ code = '''
} }
// choose a random file handle // choose a random file handle
lfs_size_t j = TEST_PRNG(&prng) % sim_file_count; lfs_size_t j = TEST_PRNG(&prng) % sim_file_count;
lfs_size_t x = sim_files[j]->x;
lfs_size_t sticky = sim_files[j]->sticky;
lfs_size_t zombie = sim_files[j]->zombie;
// this doesn't really test anything, but if we don't close // this doesn't really test anything, but if we don't close
// files eventually everything will end up zombies // files eventually everything will end up zombies
@@ -9033,6 +9140,35 @@ code = '''
sim_files[j] = sim_files[sim_file_count-1]; sim_files[j] = sim_files[sim_file_count-1];
sim_file_count -= 1; sim_file_count -= 1;
// update our sim
if (sticky && !zombie) {
// orphaned?
bool orphan = true;
for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x && !sim_files[k]->zombie) {
orphan = false;
}
}
// if we were never synced, delete from sim
if (orphan) {
for (lfs_size_t k = 0;; k++) {
if (sim[k] == x) {
memmove(&sim[k], &sim[k+1],
(sim_size-(k+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[k], &sim_prngs[k+1],
(sim_size-(k+1))*sizeof(uint32_t));
memmove(&sim_isstickys[k], &sim_isstickys[k+1],
(sim_size-(k+1))*sizeof(bool));
memmove(&sim_isdirs[k], &sim_isdirs[k+1],
(sim_size-(k+1))*sizeof(bool));
sim_size -= 1;
break;
}
}
}
}
// remove a file? // remove a file?
} else if (op == 3) { } else if (op == 3) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -9042,11 +9178,18 @@ code = '''
lfs_size_t j = TEST_PRNG(&prng) % sim_size; lfs_size_t j = TEST_PRNG(&prng) % sim_size;
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
lfsr_remove(&lfs, name) => 0;
// delete from our sim // delete from our sim
memmove(&sim[j], &sim[j+1], memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
@@ -9058,11 +9201,6 @@ code = '''
} }
} }
// delete this file
char name[256];
sprintf(name, "batman%03x", x);
lfsr_remove(&lfs, name) => 0;
// rename a file? // rename a file?
} else if (op == 4) { } else if (op == 4) {
if (sim_size == 0) { if (sim_size == 0) {
@@ -9074,31 +9212,51 @@ code = '''
lfs_size_t x = sim[j]; lfs_size_t x = sim[j];
lfs_size_t y = TEST_PRNG(&prng) % N; lfs_size_t y = TEST_PRNG(&prng) % N;
uint32_t wprng = sim_prngs[j]; uint32_t wprng = sim_prngs[j];
bool isdir = sim_isdirs[j]; bool sticky = sim_isstickys[j];
bool dir = sim_isdirs[j];
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= y) {
// renaming and replacing
if (k < sim_size && sim[k] == y && x != y) {
// type mismatch?
if (sim_isdirs[k] != dir) {
goto nonsense;
}
}
break;
}
}
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
lfsr_rename(&lfs, old_name, new_name) => 0;
// update our sim // update our sim
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= y) { if (k >= sim_size || sim[k] >= y) {
// renaming and replacing // renaming and replacing
if (k < sim_size && sim[k] == y && x != y) { if (k < sim_size && sim[k] == y && x != y) {
// type mismatch?
if (sim_isdirs[k] != isdir) {
goto nonsense;
}
// delete the original entry // delete the original entry
memmove(&sim[j], &sim[j+1], memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
sim_size -= 1; sim_size -= 1;
if (k > j) { if (k > j) {
k -= 1; k -= 1;
} }
// update the prng // update the prng/sticky/dir
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isstickys[k] = sticky;
sim_isdirs[k] = dir;
// just renaming // just renaming
} else { } else {
// first delete // first delete
@@ -9106,6 +9264,8 @@ code = '''
(sim_size-(j+1))*sizeof(lfs_size_t)); (sim_size-(j+1))*sizeof(lfs_size_t));
memmove(&sim_prngs[j], &sim_prngs[j+1], memmove(&sim_prngs[j], &sim_prngs[j+1],
(sim_size-(j+1))*sizeof(uint32_t)); (sim_size-(j+1))*sizeof(uint32_t));
memmove(&sim_isstickys[j], &sim_isstickys[j+1],
(sim_size-(j+1))*sizeof(bool));
memmove(&sim_isdirs[j], &sim_isdirs[j+1], memmove(&sim_isdirs[j], &sim_isdirs[j+1],
(sim_size-(j+1))*sizeof(bool)); (sim_size-(j+1))*sizeof(bool));
if (k > j) { if (k > j) {
@@ -9116,11 +9276,14 @@ code = '''
(sim_size-k)*sizeof(lfs_size_t)); (sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k], memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t)); (sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k], memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool)); (sim_size-k)*sizeof(bool));
sim[k] = y; sim[k] = y;
sim_prngs[k] = wprng; sim_prngs[k] = wprng;
sim_isdirs[k] = isdir; sim_isstickys[k] = sticky;
sim_isdirs[k] = dir;
} }
break; break;
} }
@@ -9138,52 +9301,52 @@ code = '''
} }
} }
// rename this file
char old_name[256];
sprintf(old_name, "batman%03x", x);
char new_name[256];
sprintf(new_name, "batman%03x", y);
lfsr_rename(&lfs, old_name, new_name) => 0;
// toss a directory into the mix // toss a directory into the mix
} else if (op == 5) { } else if (op == 5) {
// choose a pseudo-random number // choose a pseudo-random number
lfs_size_t x = TEST_PRNG(&prng) % N; lfs_size_t x = TEST_PRNG(&prng) % N;
// insert into our sim, use negative numbers for dirs
for (lfs_size_t k = 0;; k++) { for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) { if (k >= sim_size || sim[k] >= x) {
// already seen? // already seen?
if (k < sim_size && sim[k] == x) { if (k < sim_size && sim[k] == x) {
goto nonsense; goto nonsense;
} else {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = 0;
sim_isdirs[k] = true;
} }
break; break;
} }
} }
// make the directory
char name[256];
sprintf(name, "batman%03x", x);
lfsr_mkdir(&lfs, name) => 0;
// insert into our sim
for (lfs_size_t k = 0;; k++) {
if (k >= sim_size || sim[k] >= x) {
// insert
memmove(&sim[k+1], &sim[k],
(sim_size-k)*sizeof(lfs_size_t));
memmove(&sim_prngs[k+1], &sim_prngs[k],
(sim_size-k)*sizeof(uint32_t));
memmove(&sim_isstickys[k+1], &sim_isstickys[k],
(sim_size-k)*sizeof(bool));
memmove(&sim_isdirs[k+1], &sim_isdirs[k],
(sim_size-k)*sizeof(bool));
sim_size += 1;
sim[k] = x;
sim_prngs[k] = 0;
sim_isdirs[k] = true;
break;
}
}
// mark any related sim files as zombied // mark any related sim files as zombied
for (lfs_size_t k = 0; k < sim_file_count; k++) { for (lfs_size_t k = 0; k < sim_file_count; k++) {
if (sim_files[k]->x == x) { if (sim_files[k]->x == x) {
sim_files[k]->zombie = true; sim_files[k]->zombie = true;
} }
} }
// make the directory
char name[256];
sprintf(name, "batman%03x", x);
lfsr_mkdir(&lfs, name) => 0;
} }
// step the traversal // step the traversal
@@ -9209,6 +9372,10 @@ code = '''
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(info.size == 0);
} else if (sim_isstickys[j]) {
assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else { } else {
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
@@ -9233,6 +9400,10 @@ code = '''
assert(strcmp(info.name, name) == 0); assert(strcmp(info.name, name) == 0);
if (sim_isdirs[j]) { if (sim_isdirs[j]) {
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(info.size == 0);
} else if (sim_isstickys[j]) {
assert(info.type == LFS_TYPE_STICKYNOTE);
assert(info.size == 0);
} else { } else {
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE); assert(info.size == SIZE);
@@ -9246,7 +9417,8 @@ code = '''
char name[256]; char name[256];
sprintf(name, "batman%03x", sim[j]); sprintf(name, "batman%03x", sim[j]);
lfsr_file_t file; lfsr_file_t file;
lfsr_file_open(&lfs, &file, name, LFS_O_RDONLY) => LFS_ERR_ISDIR; lfsr_file_open(&lfs, &file, name, LFS_O_RDONLY)
=> LFS_ERR_ISDIR;
} else { } else {
char name[256]; char name[256];
@@ -9261,8 +9433,12 @@ code = '''
} }
uint8_t rbuf[SIZE]; uint8_t rbuf[SIZE];
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE; if (sim_isstickys[j]) {
assert(memcmp(rbuf, wbuf, SIZE) == 0); lfsr_file_read(&lfs, &file, rbuf, SIZE) => 0;
} else {
lfsr_file_read(&lfs, &file, rbuf, SIZE) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
}
lfsr_file_close(&lfs, &file) => 0; lfsr_file_close(&lfs, &file) => 0;
} }
} }
@@ -9284,6 +9460,8 @@ code = '''
// clean up sim/lfs // clean up sim/lfs
free(sim); free(sim);
free(sim_prngs); free(sim_prngs);
free(sim_isstickys);
free(sim_isdirs);
for (lfs_size_t j = 0; j < sim_file_count; j++) { for (lfs_size_t j = 0; j < sim_file_count; j++) {
lfsr_file_close(&lfs, &sim_files[j]->file) => 0; lfsr_file_close(&lfs, &sim_files[j]->file) => 0;
free(sim_files[j]); free(sim_files[j]);