Skip to content

Commit

Permalink
Added correct handling of file syncing around overwrites
Browse files Browse the repository at this point in the history
Now all of the open flags are correctly handled

Even annoying cases where we can't trust the blocks that are already
on file, such as appending existing files and writing to the middle
of files.
  • Loading branch information
geky committed Apr 23, 2017
1 parent a4e9132 commit a1d8a76
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 30 deletions.
119 changes: 95 additions & 24 deletions lfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ static int lfs_bd_read(lfs_t *lfs, lfs_block_t block,
// load to cache, first condition can no longer fail
lfs->rcache.block = block;
lfs->rcache.off = off - (off % lfs->cfg->read_size);
// TODO remove reading, should be unnecessary
err = lfs->cfg->read(lfs->cfg, lfs->rcache.block,
lfs->rcache.off, lfs->cfg->read_size,
lfs->rcache.buffer);
Expand Down Expand Up @@ -141,12 +140,6 @@ static int lfs_bd_prog(lfs_t *lfs, lfs_block_t block,
// prepare cache, first condition can no longer fail
lfs->pcache.block = block;
lfs->pcache.off = off - (off % lfs->cfg->prog_size);
err = lfs->cfg->read(lfs->cfg, lfs->pcache.block,
lfs->pcache.off, lfs->cfg->prog_size,
lfs->pcache.buffer);
if (err) {
return err;
}
}

return 0;
Expand Down Expand Up @@ -810,7 +803,7 @@ static int lfs_index_find(lfs_t *lfs, lfs_block_t head, lfs_size_t size,
lfs_off_t current = lfs_index(lfs, &(lfs_off_t){size-1});
lfs_off_t target = lfs_index(lfs, &pos);

while (current != target) {
while (current > target) {
lfs_size_t skip = lfs_min(
lfs_npw2(current-target+1) - 1,
lfs_min(lfs_ctz(current)+1, lfs->words-1) - 1);
Expand All @@ -831,6 +824,7 @@ static int lfs_index_find(lfs_t *lfs, lfs_block_t head, lfs_size_t size,
static int lfs_index_extend(lfs_t *lfs,
lfs_block_t head, lfs_size_t size,
lfs_off_t *block, lfs_block_t *off) {
// go ahead and grab a block
int err = lfs_alloc(lfs, block);
if (err) {
return err;
Expand All @@ -846,11 +840,35 @@ static int lfs_index_extend(lfs_t *lfs,
return 0;
}

lfs_off_t index = lfs_index(lfs, &(lfs_off_t){size-1}) + 1;
size -= 1;
lfs_off_t index = lfs_index(lfs, &size);
size += 1;

// just copy out the last block if it is incomplete
if (size != lfs->cfg->block_size) {
for (lfs_off_t i = 0; i < size; i++) {
uint8_t data;
int err = lfs_bd_read(lfs, head, i, 1, &data);
if (err) {
return err;
}

err = lfs_bd_prog(lfs, *block, i, 1, &data);
if (err) {
return err;
}
}

*off = size;
return 0;
}

// append block
index += 1;
lfs_size_t skips = lfs_min(lfs_ctz(index)+1, lfs->words-1);

for (lfs_off_t i = 0; i < skips; i++) {
err = lfs_bd_prog(lfs, *block, 4*i, 4, &head);
int err = lfs_bd_prog(lfs, *block, 4*i, 4, &head);
if (err) {
return err;
}
Expand Down Expand Up @@ -936,27 +954,68 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
return LFS_ERROR_EXISTS;
}

file->head = file->entry.d.u.file.head;
file->size = file->entry.d.u.file.size;
file->wpos = file->entry.d.u.file.size;
file->wpos = 0;
file->wblock = 0;
file->rpos = 0;
file->rblock = 0;

if (flags & LFS_O_TRUNC) {
file->entry.d.u.file.head = 0;
file->entry.d.u.file.size = 0;
}

if (flags & LFS_O_APPEND) {
file->wpos = file->entry.d.u.file.size;
}

return 0;
}

int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
// Store file
return lfs_file_sync(lfs, file);
}

int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
if (file->wblock == 0) {
// already in sync, may be rdonly
return 0;
}

// copy over anything after the file
lfs_off_t oldrpos = file->rpos;
lfs_off_t oldwpos = file->wpos;
file->rpos = file->wpos;
file->rblock = 0;

while (file->wpos < file->entry.d.u.file.size) {
uint8_t data;
lfs_ssize_t res = lfs_file_read(lfs, file, &data, 1);
if (res < 0) {
return res;
}

res = lfs_file_write(lfs, file, &data, 1);
if (res < 0) {
return res;
}
}

// actual file updates
file->entry.d.u.file.head = file->wblock;
file->entry.d.u.file.size = file->wpos;

file->rpos = oldrpos;
file->rblock = 0;
file->wpos = oldwpos;
file->wblock = 0;

// update dir entry
lfs_dir_t cwd;
int err = lfs_dir_fetch(lfs, &cwd, file->entry.pair);
if (err) {
return err;
}

file->entry.d.u.file.head = file->head;
file->entry.d.u.file.size = file->size;

return lfs_dir_commit(lfs, &cwd, &file->entry, NULL);
}

Expand All @@ -966,14 +1025,16 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
lfs_size_t nsize = size;

while (nsize > 0) {
// check if we need a new block
if (!file->wblock || file->woff == lfs->cfg->block_size) {
int err = lfs_index_extend(lfs, file->head, file->wpos,
int err = lfs_index_extend(lfs, file->wblock, file->wpos,
&file->wblock, &file->woff);
if (err) {
return err;
}
}

// program as much as we can in current block
lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->woff);
int err = lfs_bd_prog(lfs, file->wblock, file->woff, diff, data);
if (err) {
Expand All @@ -985,9 +1046,16 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
data += diff;
nsize -= diff;

if (file->wpos > file->size) {
file->size = file->wpos;
file->head = file->wblock;
if (file->flags & LFS_O_APPEND) {
file->entry.d.u.file.head = file->wblock;
file->entry.d.u.file.size = file->wpos;
}
}

if (file->flags & LFS_O_SYNC) {
int err = lfs_file_sync(lfs, file);
if (err) {
return err;
}
}

Expand All @@ -997,18 +1065,21 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
void *buffer, lfs_size_t size) {
uint8_t *data = buffer;
size = lfs_min(size, file->size - file->rpos);
size = lfs_min(size, file->entry.d.u.file.size - file->rpos);
lfs_size_t nsize = size;

while (nsize > 0) {
// check if we need a new block
if (!file->rblock || file->roff == lfs->cfg->block_size) {
int err = lfs_index_find(lfs, file->head, file->size, file->rpos,
&file->rblock, &file->roff);
int err = lfs_index_find(lfs,
file->entry.d.u.file.head, file->entry.d.u.file.size,
file->rpos, &file->rblock, &file->roff);
if (err) {
return err;
}
}

// read as much as we can in current block
lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->roff);
int err = lfs_bd_read(lfs, file->rblock, file->roff, diff, data);
if (err) {
Expand Down
9 changes: 3 additions & 6 deletions lfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ typedef struct lfs_entry {
} lfs_entry_t;

typedef struct lfs_file {
lfs_block_t head;
lfs_size_t size;
struct lfs_entry entry;
int flags;

lfs_off_t wpos;
lfs_block_t wblock;
Expand All @@ -132,10 +132,6 @@ typedef struct lfs_file {
lfs_off_t rpos;
lfs_block_t rblock;
lfs_off_t roff;

int flags;

struct lfs_entry entry;
} lfs_file_t;

typedef struct lfs_dir {
Expand Down Expand Up @@ -203,6 +199,7 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info);
int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
const char *path, int flags);
int lfs_file_close(lfs_t *lfs, lfs_file_t *file);
int lfs_file_sync(lfs_t *lfs, lfs_file_t *file);
lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
const void *buffer, lfs_size_t size);
lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
Expand Down

0 comments on commit a1d8a76

Please sign in to comment.