Fixed a handful of bugs as result of testing

This commit is contained in:
Christopher Haster
2018-03-18 20:36:48 -05:00
parent d8cadecba6
commit 701e4fa438
3 changed files with 126 additions and 105 deletions

217
lfs.c
View File

@@ -821,7 +821,7 @@ static int lfs_dir_update(lfs_t *lfs, lfs_dir_t *dir,
lfs_entry_t oldentry = { lfs_entry_t oldentry = {
.off = entry->off, .off = entry->off,
.size = entry->size - diff, .size = entry->size - diff,
.d.type = entry->d.type | LFS_STRUCT_MOVED, .d.type = entry->d.type | LFS_STRUCT_MOVED, // TODO FIXME when changing type??
}; };
// mark as moving // mark as moving
@@ -846,7 +846,12 @@ static int lfs_dir_update(lfs_t *lfs, lfs_dir_t *dir,
} }
// remove old entry // remove old entry
err = lfs_dir_remove(lfs, dir, &oldentry); err = lfs_dir_fetch(lfs, &olddir, olddir.pair);
if (err) {
return err;
}
err = lfs_dir_remove(lfs, &olddir, &oldentry);
if (err) { if (err) {
return err; return err;
} }
@@ -1579,78 +1584,69 @@ relocate:;
} }
static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
if (file->flags & LFS_F_INLINE) {
// do nothing since we won't need the cache for anything else
if (file->flags & LFS_F_READING) {
file->flags &= ~LFS_F_READING;
}
if (file->flags & LFS_F_WRITING) {
file->size = lfs_max(file->pos, file->size);
file->flags &= ~LFS_F_WRITING;
file->flags |= LFS_F_DIRTY;
}
return 0;
}
if (file->flags & LFS_F_READING) { if (file->flags & LFS_F_READING) {
// just drop read cache if (!(file->flags & LFS_F_INLINE)) {
file->cache.block = 0xffffffff; // just drop read cache
file->cache.block = 0xffffffff;
}
file->flags &= ~LFS_F_READING; file->flags &= ~LFS_F_READING;
} }
if (file->flags & LFS_F_WRITING) { if (file->flags & LFS_F_WRITING) {
lfs_off_t pos = file->pos; lfs_off_t pos = file->pos;
// copy over anything after current branch if (!(file->flags & LFS_F_INLINE)) {
lfs_file_t orig = { // copy over anything after current branch
.head = file->head, lfs_file_t orig = {
.size = file->size, .head = file->head,
.flags = LFS_O_RDONLY, .size = file->size,
.pos = file->pos, .flags = LFS_O_RDONLY,
.cache = lfs->rcache, .pos = file->pos,
}; .cache = lfs->rcache,
lfs->rcache.block = 0xffffffff; };
lfs->rcache.block = 0xffffffff;
while (file->pos < file->size) { while (file->pos < file->size) {
// copy over a byte at a time, leave it up to caching // copy over a byte at a time, leave it up to caching
// to make this efficient // to make this efficient
uint8_t data; uint8_t data;
lfs_ssize_t res = lfs_file_read(lfs, &orig, &data, 1); lfs_ssize_t res = lfs_file_read(lfs, &orig, &data, 1);
if (res < 0) { if (res < 0) {
return res; return res;
} }
res = lfs_file_write(lfs, file, &data, 1); res = lfs_file_write(lfs, file, &data, 1);
if (res < 0) { if (res < 0) {
return res; return res;
} }
// keep our reference to the rcache in sync // keep our reference to the rcache in sync
if (lfs->rcache.block != 0xffffffff) { if (lfs->rcache.block != 0xffffffff) {
orig.cache.block = 0xffffffff; orig.cache.block = 0xffffffff;
lfs->rcache.block = 0xffffffff; lfs->rcache.block = 0xffffffff;
}
}
// write out what we have
while (true) {
int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache);
if (err) {
if (err == LFS_ERR_CORRUPT) {
goto relocate;
} }
return err;
} }
break; // write out what we have
while (true) {
int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache);
if (err) {
if (err == LFS_ERR_CORRUPT) {
goto relocate;
}
return err;
}
break;
relocate: relocate:
LFS_DEBUG("Bad block at %d", file->block); LFS_DEBUG("Bad block at %d", file->block);
err = lfs_file_relocate(lfs, file); err = lfs_file_relocate(lfs, file);
if (err) { if (err) {
return err; return err;
}
} }
} else {
file->size = lfs_max(file->pos, file->size);
} }
// actual file updates // actual file updates
@@ -1691,7 +1687,23 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
} }
LFS_ASSERT((0xf & entry.d.type) == LFS_TYPE_REG); LFS_ASSERT((0xf & entry.d.type) == LFS_TYPE_REG);
if (file->flags & LFS_F_INLINE) { if (!(file->flags & LFS_F_INLINE)) {
lfs_ssize_t diff = sizeof(entry.d)-4 - entry.d.elen;
entry.d.type = LFS_STRUCT_CTZ | LFS_TYPE_REG;
entry.d.elen = sizeof(entry.d)-4;
entry.d.u.file.head = file->head;
entry.d.u.file.size = file->size;
entry.size = 4 + entry.d.elen + entry.d.alen + entry.d.nlen;
// TODO combine down?
err = lfs_dir_update(lfs, &cwd, &entry,
&(struct lfs_region){
0, diff,
lfs_commit_mem, &entry.d, sizeof(entry.d)});
if (err) {
return err;
}
} else {
lfs_ssize_t diff = file->size - entry.d.elen; lfs_ssize_t diff = file->size - entry.d.elen;
entry.d.type = LFS_STRUCT_INLINE | LFS_TYPE_REG; entry.d.type = LFS_STRUCT_INLINE | LFS_TYPE_REG;
entry.d.elen = file->size; entry.d.elen = file->size;
@@ -1707,22 +1719,6 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
if (err) { if (err) {
return err; return err;
} }
} else {
lfs_ssize_t diff = sizeof(entry.d) - entry.d.elen;
entry.d.type = LFS_STRUCT_CTZ | LFS_TYPE_REG;
entry.d.elen = sizeof(entry.d);
entry.d.u.file.head = file->head;
entry.d.u.file.size = file->size;
entry.size = 4 + entry.d.elen + entry.d.alen + entry.d.nlen;
// TODO combine up?
err = lfs_dir_update(lfs, &cwd, &entry,
&(struct lfs_region){
0, diff,
lfs_commit_mem, &entry.d, sizeof(entry.d)});
if (err) {
return err;
}
} }
file->flags &= ~LFS_F_DIRTY; file->flags &= ~LFS_F_DIRTY;
@@ -1761,16 +1757,16 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
// check if we need a new block // check if we need a new block
if (!(file->flags & LFS_F_READING) || if (!(file->flags & LFS_F_READING) ||
file->off == lfs->cfg->block_size) { file->off == lfs->cfg->block_size) {
if (file->flags & LFS_F_INLINE) { if (!(file->flags & LFS_F_INLINE)) {
file->block = 0xfffffffe;
file->off = file->pos;
} else {
int err = lfs_ctz_find(lfs, &file->cache, NULL, int err = lfs_ctz_find(lfs, &file->cache, NULL,
file->head, file->size, file->head, file->size,
file->pos, &file->block, &file->off); file->pos, &file->block, &file->off);
if (err) { if (err) {
return err; return err;
} }
} else {
file->block = 0xfffffffe;
file->off = file->pos;
} }
file->flags |= LFS_F_READING; file->flags |= LFS_F_READING;
@@ -1830,8 +1826,14 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
// TODO combine with block allocation? // TODO combine with block allocation?
// TODO need to move out if no longer fits in block also // TODO need to move out if no longer fits in block also
// TODO store INLINE_MAX in superblock? // TODO store INLINE_MAX in superblock?
if ((file->pos + nsize >= LFS_INLINE_MAX) || // TODO what if inline files is > block size (ie 128)
(file->pos + nsize >= lfs->cfg->read_size)) { if ((file->flags & LFS_F_INLINE) && (
(file->pos + nsize >= LFS_INLINE_MAX) ||
(file->pos + nsize >= lfs->cfg->read_size))) {
file->block = 0xfffffffe;
file->off = file->pos;
lfs_alloc_ack(lfs);
int err = lfs_file_relocate(lfs, file); int err = lfs_file_relocate(lfs, file);
if (err) { if (err) {
file->flags |= LFS_F_ERRED; file->flags |= LFS_F_ERRED;
@@ -1849,10 +1851,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
// check if we need a new block // check if we need a new block
if (!(file->flags & LFS_F_WRITING) || if (!(file->flags & LFS_F_WRITING) ||
file->off == lfs->cfg->block_size) { file->off == lfs->cfg->block_size) {
if (file->flags & LFS_F_INLINE) { if (!(file->flags & LFS_F_INLINE)) {
file->block = 0xfffffffe;
file->off = file->pos;
} else {
if (!(file->flags & LFS_F_WRITING) && file->pos > 0) { if (!(file->flags & LFS_F_WRITING) && file->pos > 0) {
// find out which block we're extending from // find out which block we're extending from
int err = lfs_ctz_find(lfs, &file->cache, NULL, int err = lfs_ctz_find(lfs, &file->cache, NULL,
@@ -1876,6 +1875,9 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
file->flags |= LFS_F_ERRED; file->flags |= LFS_F_ERRED;
return err; return err;
} }
} else {
file->block = 0xfffffffe;
file->off = file->pos;
} }
file->flags |= LFS_F_WRITING; file->flags |= LFS_F_WRITING;
@@ -1944,7 +1946,6 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
} }
// TODO handle inlining? // TODO handle inlining?
// TODO note at least needs tests for trunc on inlined file
int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
if ((file->flags & 3) == LFS_O_RDONLY) { if ((file->flags & 3) == LFS_O_RDONLY) {
return LFS_ERR_BADF; return LFS_ERR_BADF;
@@ -2179,6 +2180,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
&(struct lfs_region){ &(struct lfs_region){
0, 0, 0, 0,
lfs_commit_mem, &oldentry.d.type, 1}); lfs_commit_mem, &oldentry.d.type, 1});
oldentry.d.type &= ~LFS_STRUCT_MOVED;
if (err) { if (err) {
return err; return err;
} }
@@ -2193,26 +2195,39 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
newentry.d = oldentry.d; newentry.d = oldentry.d;
newentry.d.type &= ~LFS_STRUCT_MOVED; newentry.d.type &= ~LFS_STRUCT_MOVED;
newentry.d.nlen = strlen(newpath); newentry.d.nlen = strlen(newpath);
newentry.size = 4 + newentry.d.elen + newentry.d.alen + newentry.d.nlen;
if (prevexists) { if (prevexists) {
err = lfs_dir_update(lfs, &newcwd, &newentry, err = lfs_dir_update(lfs, &newcwd, &newentry,
&(struct lfs_region){ &(struct lfs_region){
0, 0, 0, newentry.size - preventry.size,
lfs_commit_mem, &newentry.d, sizeof(newentry.d), lfs_commit_disk, &(struct lfs_commit_disk){
&(struct lfs_region){ oldcwd.pair[0], oldentry.off,
sizeof(newentry.d), 0, &(struct lfs_region){
lfs_commit_mem, newpath, newentry.d.nlen}}); 0, 0,
lfs_commit_mem, &newentry.d, 4,
&(struct lfs_region){
newentry.size - newentry.d.nlen,
+newentry.d.nlen-oldentry.d.nlen,
lfs_commit_mem, newpath, newentry.d.nlen}}},
oldentry.size});
if (err) { if (err) {
return err; return err;
} }
} else { } else {
err = lfs_dir_append(lfs, &newcwd, &newentry, err = lfs_dir_append(lfs, &newcwd, &newentry,
&(struct lfs_region){ &(struct lfs_region){
0, +sizeof(newentry.d), 0, +newentry.size,
lfs_commit_mem, &newentry.d, sizeof(newentry.d), lfs_commit_disk, &(struct lfs_commit_disk){
&(struct lfs_region){ oldcwd.pair[0], oldentry.off,
0, +newentry.d.nlen, &(struct lfs_region){
lfs_commit_mem, newpath, newentry.d.nlen}}); 0, 0,
lfs_commit_mem, &newentry.d, 4,
&(struct lfs_region){
newentry.size - newentry.d.nlen,
+newentry.d.nlen-oldentry.d.nlen,
lfs_commit_mem, newpath, newentry.d.nlen}}},
oldentry.size});
if (err) { if (err) {
return err; return err;
} }
@@ -2507,7 +2522,7 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) {
// iterate over any open files // iterate over any open files
for (lfs_file_t *f = lfs->files; f; f = f->next) { for (lfs_file_t *f = lfs->files; f; f = f->next) {
if (f->flags & LFS_F_DIRTY) { if ((f->flags & LFS_F_DIRTY) && !(f->flags & LFS_F_INLINE)) {
int err = lfs_ctz_traverse(lfs, &lfs->rcache, &f->cache, int err = lfs_ctz_traverse(lfs, &lfs->rcache, &f->cache,
f->head, f->size, cb, data); f->head, f->size, cb, data);
if (err) { if (err) {
@@ -2515,7 +2530,7 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) {
} }
} }
if (f->flags & LFS_F_WRITING) { if ((f->flags & LFS_F_WRITING) && !(f->flags & LFS_F_INLINE)) {
int err = lfs_ctz_traverse(lfs, &lfs->rcache, &f->cache, int err = lfs_ctz_traverse(lfs, &lfs->rcache, &f->cache,
f->block, f->pos, cb, data); f->block, f->pos, cb, data);
if (err) { if (err) {

View File

@@ -274,9 +274,12 @@ TEST
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
// create one block whole for half a directory // create one block hole for half a directory
lfs_file_open(&lfs, &file[0], "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file[0], "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file[0], (void*)"hi", 2) => 2; for (lfs_size_t i = 0; i < cfg.block_size; i += 2) {
memcpy(&buffer[i], "hi", 2);
}
lfs_file_write(&lfs, &file[0], buffer, cfg.block_size) => cfg.block_size;
lfs_file_close(&lfs, &file[0]) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file[0], "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
@@ -295,7 +298,10 @@ tests/test.py << TEST
lfs_mkdir(&lfs, "splitdir") => 0; lfs_mkdir(&lfs, "splitdir") => 0;
lfs_file_open(&lfs, &file[0], "splitdir/bump", lfs_file_open(&lfs, &file[0], "splitdir/bump",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file[0], buffer, size) => LFS_ERR_NOSPC; for (lfs_size_t i = 0; i < cfg.block_size; i += 2) {
memcpy(&buffer[i], "hi", 2);
}
lfs_file_write(&lfs, &file[0], buffer, cfg.block_size) => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file[0]) => 0; lfs_file_close(&lfs, &file[0]) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;

View File

@@ -88,7 +88,7 @@ do
rm -rf blocks rm -rf blocks
mkdir blocks mkdir blocks
lfs_mktree lfs_mktree
chmod a-w blocks/$(printf '%x' $i) chmod a-w blocks/$(printf '%x' $i) || true
lfs_mktree lfs_mktree
lfs_chktree lfs_chktree
done done