diff --git a/lfs.c b/lfs.c index d5d7b2e2bae..106eb035d61 100644 --- a/lfs.c +++ b/lfs.c @@ -9,46 +9,35 @@ #include #include +#include -/// Block device operations /// -static int lfs_bd_flush(lfs_t *lfs) { - if (lfs->pcache.off != -1) { - int err = lfs->cfg->prog(lfs->cfg, lfs->pcache.block, - lfs->pcache.off, lfs->pcache.buffer, lfs->cfg->prog_size); - if (err) { - return err; - } - - lfs->pcache.off = -1; - } - - return 0; -} - -static int lfs_bd_read(lfs_t *lfs, lfs_block_t block, +/// Caching block device operations /// +static int lfs_cache_read(lfs_t *lfs, lfs_cache_t *rcache, + const lfs_cache_t *pcache, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) { uint8_t *data = buffer; - // flush overlapping programs while (size > 0) { - if (block == lfs->pcache.block && off >= lfs->pcache.off && - off < lfs->pcache.off + lfs->cfg->prog_size) { - // is already in cache? + if (pcache && block == pcache->block && off >= pcache->off && + off < pcache->off + lfs->cfg->prog_size) { + // is already in pcache? lfs_size_t diff = lfs_min(size, - lfs->cfg->prog_size - (off-lfs->pcache.off)); - memcpy(data, &lfs->pcache.buffer[off-lfs->pcache.off], diff); + lfs->cfg->prog_size - (off-pcache->off)); + memcpy(data, &pcache->buffer[off-pcache->off], diff); data += diff; off += diff; size -= diff; continue; - } else if (block == lfs->rcache.block && off >= lfs->rcache.off && - off < lfs->rcache.off + lfs->cfg->read_size) { - // is already in cache? + } + + if (block == rcache->block && off >= rcache->off && + off < rcache->off + lfs->cfg->read_size) { + // is already in rcache? lfs_size_t diff = lfs_min(size, - lfs->cfg->read_size - (off-lfs->rcache.off)); - memcpy(data, &lfs->rcache.buffer[off-lfs->rcache.off], diff); + lfs->cfg->read_size - (off-rcache->off)); + memcpy(data, &rcache->buffer[off-rcache->off], diff); data += diff; off += diff; @@ -56,14 +45,7 @@ static int lfs_bd_read(lfs_t *lfs, lfs_block_t block, continue; } - // write out pending programs - int err = lfs_bd_flush(lfs); - if (err) { - return err; - } - - if (off % lfs->cfg->read_size == 0 && - size >= lfs->cfg->read_size) { + if (off % lfs->cfg->read_size == 0 && size >= lfs->cfg->read_size) { // bypass cache? lfs_size_t diff = size - (size % lfs->cfg->read_size); int err = lfs->cfg->read(lfs->cfg, block, off, data, diff); @@ -78,10 +60,10 @@ 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); - err = lfs->cfg->read(lfs->cfg, lfs->rcache.block, - lfs->rcache.off, lfs->rcache.buffer, lfs->cfg->read_size); + rcache->block = block; + rcache->off = off - (off % lfs->cfg->read_size); + int err = lfs->cfg->read(lfs->cfg, rcache->block, + rcache->off, rcache->buffer, lfs->cfg->read_size); if (err) { return err; } @@ -90,34 +72,50 @@ static int lfs_bd_read(lfs_t *lfs, lfs_block_t block, return 0; } -static int lfs_bd_prog(lfs_t *lfs, lfs_block_t block, - lfs_off_t off, const void *buffer, lfs_size_t size) { - const uint8_t *data = buffer; +static int lfs_cache_flush(lfs_t *lfs, lfs_cache_t *cache) { + if (cache->off != -1) { + int err = lfs->cfg->prog(lfs->cfg, cache->block, + cache->off, cache->buffer, lfs->cfg->prog_size); + if (err) { + return err; + } - if (block == lfs->rcache.block) { - // invalidate read cache - lfs->rcache.off = -1; + cache->off = -1; } + return 0; +} + +static int lfs_cache_prog(lfs_t *lfs, lfs_cache_t *cache, lfs_block_t block, + lfs_off_t off, const void *buffer, lfs_size_t size) { + const uint8_t *data = buffer; + while (size > 0) { - if (block == lfs->pcache.block && off >= lfs->pcache.off && - off < lfs->pcache.off + lfs->cfg->prog_size) { + if (block == cache->block && off >= cache->off && + off < cache->off + lfs->cfg->prog_size) { // is already in cache? lfs_size_t diff = lfs_min(size, - lfs->cfg->prog_size - (off-lfs->pcache.off)); - memcpy(&lfs->pcache.buffer[off-lfs->pcache.off], data, diff); + lfs->cfg->prog_size - (off-cache->off)); + memcpy(&cache->buffer[off-cache->off], data, diff); data += diff; off += diff; size -= diff; + + if (off % lfs->cfg->prog_size == 0) { + // eagerly flush out cache if we fill up + int err = lfs_cache_flush(lfs, cache); + if (err) { + return err; + } + } + continue; } - // write out pending programs - int err = lfs_bd_flush(lfs); - if (err) { - return err; - } + // cache must have been flushed, either by programming and + // entire block or manually flushing the cache + assert(cache->off == -1); if (off % lfs->cfg->prog_size == 0 && size >= lfs->cfg->prog_size) { @@ -135,19 +133,35 @@ 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); + cache->block = block; + cache->off = off - (off % lfs->cfg->prog_size); } return 0; } -static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) { + +/// General lfs block device operations /// +static int lfs_read(lfs_t *lfs, lfs_block_t block, + lfs_off_t off, void *buffer, lfs_size_t size) { + // if we ever do more than writes to alternating pairs, + // this may need to consider pcache + return lfs_cache_read(lfs, &lfs->rcache, NULL, + block, off, buffer, size); +} + +static int lfs_prog(lfs_t *lfs, lfs_block_t block, + lfs_off_t off, const void *buffer, lfs_size_t size) { + return lfs_cache_prog(lfs, &lfs->pcache, + block, off, buffer, size); +} + +static int lfs_erase(lfs_t *lfs, lfs_block_t block) { return lfs->cfg->erase(lfs->cfg, block); } -static int lfs_bd_sync(lfs_t *lfs) { - int err = lfs_bd_flush(lfs); +static int lfs_sync(lfs_t *lfs) { + int err = lfs_cache_flush(lfs, &lfs->pcache); if (err) { return err; } @@ -155,13 +169,13 @@ static int lfs_bd_sync(lfs_t *lfs) { return lfs->cfg->sync(lfs->cfg); } -static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block, +static int lfs_cmp(lfs_t *lfs, lfs_block_t block, lfs_off_t off, lfs_size_t size, const void *buffer) { const uint8_t *data = buffer; for (lfs_off_t i = 0; i < size; i++) { uint8_t c; - int err = lfs_bd_read(lfs, block, off+i, &c, 1); + int err = lfs_read(lfs, block, off+i, &c, 1); if (err) { return err; } @@ -250,7 +264,7 @@ static inline void lfs_pairswap(lfs_block_t pair[2]) { } static inline bool lfs_pairisnull(const lfs_block_t pair[2]) { - return !pair[0] || !pair[1]; + return !pair[0] && !pair[1]; } static inline int lfs_paircmp( @@ -276,7 +290,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir) { // rather than clobbering one of the blocks we just pretend // the revision may be valid - int err = lfs_bd_read(lfs, dir->pair[0], 0, &dir->d.rev, 4); + int err = lfs_read(lfs, dir->pair[0], 0, &dir->d.rev, 4); if (err) { return err; } @@ -301,7 +315,7 @@ static int lfs_dir_fetch(lfs_t *lfs, // check both blocks for the most recent revision for (int i = 0; i < 2; i++) { struct lfs_disk_dir test; - int err = lfs_bd_read(lfs, tpair[i], 0, &test, sizeof(test)); + int err = lfs_read(lfs, tpair[i], 0, &test, sizeof(test)); if (err) { return err; } @@ -315,7 +329,7 @@ static int lfs_dir_fetch(lfs_t *lfs, for (lfs_off_t j = sizeof(test); j < lfs->cfg->block_size; j += 4) { uint32_t word; - int err = lfs_bd_read(lfs, tpair[i], j, &word, 4); + int err = lfs_read(lfs, tpair[i], j, &word, 4); if (err) { return err; } @@ -349,14 +363,14 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, dir->d.rev += 1; lfs_pairswap(dir->pair); - int err = lfs_bd_erase(lfs, dir->pair[0]); + int err = lfs_erase(lfs, dir->pair[0]); if (err) { return err; } uint32_t crc = 0xffffffff; crc = lfs_crc(crc, &dir->d, sizeof(dir->d)); - err = lfs_bd_prog(lfs, dir->pair[0], 0, &dir->d, sizeof(dir->d)); + err = lfs_prog(lfs, dir->pair[0], 0, &dir->d, sizeof(dir->d)); if (err) { return err; } @@ -366,7 +380,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, while (off < size) { if (entry && off == entry->off) { crc = lfs_crc(crc, &entry->d, sizeof(entry->d)); - int err = lfs_bd_prog(lfs, dir->pair[0], + int err = lfs_prog(lfs, dir->pair[0], off, &entry->d, sizeof(entry->d)); if (err) { return err; @@ -375,7 +389,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, if (data) { crc = lfs_crc(crc, data, entry->d.len - sizeof(entry->d)); - int err = lfs_bd_prog(lfs, dir->pair[0], + int err = lfs_prog(lfs, dir->pair[0], off, data, entry->d.len - sizeof(entry->d)); if (err) { return err; @@ -384,13 +398,13 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, } } else { uint8_t data; - int err = lfs_bd_read(lfs, dir->pair[1], off, &data, 1); + int err = lfs_read(lfs, dir->pair[1], off, &data, 1); if (err) { return err; } crc = lfs_crc(crc, &data, 1); - err = lfs_bd_prog(lfs, dir->pair[0], off, &data, 1); + err = lfs_prog(lfs, dir->pair[0], off, &data, 1); if (err) { return err; } @@ -402,7 +416,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, while (off < lfs->cfg->block_size-4) { uint8_t data = 0xff; crc = lfs_crc(crc, &data, 1); - err = lfs_bd_prog(lfs, dir->pair[0], off, &data, 1); + err = lfs_prog(lfs, dir->pair[0], off, &data, 1); if (err) { return err; } @@ -410,12 +424,12 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, off += 1; } - err = lfs_bd_prog(lfs, dir->pair[0], lfs->cfg->block_size-4, &crc, 4); + err = lfs_prog(lfs, dir->pair[0], lfs->cfg->block_size-4, &crc, 4); if (err) { return err; } - return lfs_bd_sync(lfs); + return lfs_sync(lfs); } static int lfs_dir_shift(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { @@ -423,14 +437,14 @@ static int lfs_dir_shift(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { dir->d.size -= entry->d.len; lfs_pairswap(dir->pair); - int err = lfs_bd_erase(lfs, dir->pair[0]); + int err = lfs_erase(lfs, dir->pair[0]); if (err) { return err; } uint32_t crc = 0xffffffff; crc = lfs_crc(crc, &dir->d, sizeof(dir->d)); - err = lfs_bd_prog(lfs, dir->pair[0], 0, &dir->d, sizeof(dir->d)); + err = lfs_prog(lfs, dir->pair[0], 0, &dir->d, sizeof(dir->d)); if (err) { return err; } @@ -443,13 +457,13 @@ static int lfs_dir_shift(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { roff += entry->d.len; } else { uint8_t data; - int err = lfs_bd_read(lfs, dir->pair[1], roff, &data, 1); + int err = lfs_read(lfs, dir->pair[1], roff, &data, 1); if (err) { return err; } crc = lfs_crc(crc, &data, 1); - err = lfs_bd_prog(lfs, dir->pair[0], woff, &data, 1); + err = lfs_prog(lfs, dir->pair[0], woff, &data, 1); if (err) { return err; } @@ -462,7 +476,7 @@ static int lfs_dir_shift(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { while (woff < lfs->cfg->block_size-4) { uint8_t data = 0xff; crc = lfs_crc(crc, &data, 1); - err = lfs_bd_prog(lfs, dir->pair[0], woff, &data, 1); + err = lfs_prog(lfs, dir->pair[0], woff, &data, 1); if (err) { return err; } @@ -471,12 +485,12 @@ static int lfs_dir_shift(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { woff += 1; } - err = lfs_bd_prog(lfs, dir->pair[0], lfs->cfg->block_size-4, &crc, 4); + err = lfs_prog(lfs, dir->pair[0], lfs->cfg->block_size-4, &crc, 4); if (err) { return err; } - return lfs_bd_sync(lfs); + return lfs_sync(lfs); } static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir, @@ -572,7 +586,7 @@ static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { continue; } - int err = lfs_bd_read(lfs, dir->pair[0], dir->off, + int err = lfs_read(lfs, dir->pair[0], dir->off, &entry->d, sizeof(entry->d)); if (err) { return err; @@ -641,7 +655,7 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir, continue; } - int ret = lfs_bd_cmp(lfs, dir->pair[0], + int ret = lfs_cmp(lfs, dir->pair[0], entry->off + sizeof(entry->d), pathlen, pathname); if (ret < 0) { return ret; @@ -788,7 +802,7 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { info->size = entry.d.u.file.size; } - err = lfs_bd_read(lfs, dir->pair[0], entry.off + sizeof(entry.d), + err = lfs_read(lfs, dir->pair[0], entry.off + sizeof(entry.d), info->name, entry.d.len - sizeof(entry.d)); if (err) { return err; @@ -840,7 +854,7 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) { } -/// Index list operations /// +/// File index list operations /// static int lfs_index(lfs_t *lfs, lfs_off_t *off) { lfs_off_t i = 0; @@ -853,7 +867,9 @@ static int lfs_index(lfs_t *lfs, lfs_off_t *off) { return i; } -static int lfs_index_find(lfs_t *lfs, lfs_block_t head, lfs_size_t size, +static int lfs_index_find(lfs_t *lfs, + lfs_cache_t *rcache, const lfs_cache_t *pcache, + lfs_block_t head, lfs_size_t size, lfs_size_t pos, lfs_block_t *block, lfs_off_t *off) { if (size == 0) { *block = 0; @@ -869,7 +885,7 @@ static int lfs_index_find(lfs_t *lfs, lfs_block_t head, lfs_size_t size, lfs_npw2(current-target+1) - 1, lfs_min(lfs_ctz(current)+1, lfs->words-1) - 1); - int err = lfs_bd_read(lfs, head, 4*skip, &head, 4); + int err = lfs_cache_read(lfs, rcache, pcache, head, 4*skip, &head, 4); if (err) { return err; } @@ -883,6 +899,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_cache_t *rcache, lfs_cache_t *pcache, lfs_block_t head, lfs_size_t size, lfs_off_t *block, lfs_block_t *off) { // go ahead and grab a block @@ -891,7 +908,7 @@ static int lfs_index_extend(lfs_t *lfs, return err; } - err = lfs_bd_erase(lfs, *block); + err = lfs_erase(lfs, *block); if (err) { return err; } @@ -909,12 +926,12 @@ static int lfs_index_extend(lfs_t *lfs, 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, &data, 1); + int err = lfs_cache_read(lfs, rcache, NULL, head, i, &data, 1); if (err) { return err; } - err = lfs_bd_prog(lfs, *block, i, &data, 1); + err = lfs_cache_prog(lfs, pcache, *block, i, &data, 1); if (err) { return err; } @@ -929,13 +946,13 @@ static int lfs_index_extend(lfs_t *lfs, lfs_size_t skips = lfs_min(lfs_ctz(index)+1, lfs->words-1); for (lfs_off_t i = 0; i < skips; i++) { - int err = lfs_bd_prog(lfs, *block, 4*i, &head, 4); + int err = lfs_cache_prog(lfs, pcache, *block, 4*i, &head, 4); if (err) { return err; } if (i != skips-1) { - err = lfs_bd_read(lfs, head, 4*i, &head, 4); + err = lfs_cache_read(lfs, rcache, NULL, head, 4*i, &head, 4); if (err) { return err; } @@ -947,6 +964,7 @@ static int lfs_index_extend(lfs_t *lfs, } static int lfs_index_traverse(lfs_t *lfs, + lfs_cache_t *rcache, const lfs_cache_t *pcache, lfs_block_t head, lfs_size_t size, int (*cb)(void*, lfs_block_t), void *data) { if (size == 0) { @@ -965,7 +983,7 @@ static int lfs_index_traverse(lfs_t *lfs, return 0; } - err = lfs_bd_read(lfs, head, 0, &head, 4); + err = lfs_cache_read(lfs, rcache, pcache, head, 0, &head, 4); if (err) { return err; } @@ -1016,19 +1034,34 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, // setup file struct file->pair[0] = cwd.pair[0]; file->pair[1] = cwd.pair[1]; - file->off = entry.off; + file->poff = entry.off; file->head = entry.d.u.file.head; file->size = entry.d.u.file.size; file->flags = flags; file->pos = 0; - file->wblock = 0; - file->rblock = 0; + file->block = 0; if (flags & LFS_O_TRUNC) { file->head = 0; file->size = 0; } + // allocate buffer if needed + file->cache.off = -1; + if (lfs->cfg->file_buffer) { + file->cache.buffer = lfs->cfg->file_buffer; + } else if ((file->flags & 3) == LFS_O_RDONLY) { + file->cache.buffer = malloc(lfs->cfg->read_size); + if (!file->cache.buffer) { + return LFS_ERR_NOMEM; + } + } else { + file->cache.buffer = malloc(lfs->cfg->prog_size); + if (!file->cache.buffer) { + return LFS_ERR_NOMEM; + } + } + // add to list of files file->next = lfs->files; lfs->files = file; @@ -1047,16 +1080,22 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { } } + // clean up memory + if (!lfs->cfg->file_buffer) { + free(file->cache.buffer); + } + return err; } static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { - if (file->rblock) { - // just drop read block - file->rblock = 0; + if (file->flags & LFS_F_READING) { + // just drop read cache + file->cache.off = -1; + file->flags &= ~LFS_F_READING; } - if (file->wblock) { + if (file->flags & LFS_F_WRITING) { lfs_off_t pos = file->pos; // copy over anything after current branch @@ -1065,10 +1104,13 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { .size = file->size, .flags = LFS_O_RDONLY, .pos = file->pos, - .rblock = 0, + .cache = lfs->rcache, }; + lfs->rcache.off = -1; while (file->pos < file->size) { + // copy over a byte at a time, leave it up to caching + // to make this efficient uint8_t data; lfs_ssize_t res = lfs_file_read(lfs, &orig, &data, 1); if (res < 0) { @@ -1079,13 +1121,25 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { if (res < 0) { return res; } + + // keep our reference to the rcache in sync + if (lfs->rcache.off != -1) { + orig.cache.off = -1; + lfs->rcache.off = -1; + } + } + + // write out what we have + int err = lfs_cache_flush(lfs, &file->cache); + if (err) { + return err; } // actual file updates - file->head = file->wblock; + file->head = file->block; file->size = file->pos; - file->wblock = 0; - file->flags |= LFS_O_DIRTY; + file->flags &= ~LFS_F_WRITING; + file->flags |= LFS_F_DIRTY; file->pos = pos; } @@ -1099,7 +1153,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { return err; } - if (file->flags & LFS_O_DIRTY) { + if (file->flags & LFS_F_DIRTY) { // update dir entry lfs_dir_t cwd; int err = lfs_dir_fetch(lfs, &cwd, file->pair); @@ -1107,8 +1161,8 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { return err; } - lfs_entry_t entry = {.off = file->off}; - err = lfs_bd_read(lfs, cwd.pair[0], entry.off, + lfs_entry_t entry = {.off = file->poff}; + err = lfs_read(lfs, cwd.pair[0], entry.off, &entry.d, sizeof(entry.d)); if (err) { return err; @@ -1127,7 +1181,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { return err; } - file->flags &= ~LFS_O_DIRTY; + file->flags &= ~LFS_F_DIRTY; } return 0; @@ -1142,7 +1196,7 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, return LFS_ERR_INVAL; } - if (file->wblock) { + if (file->flags & LFS_F_WRITING) { // flush out any writes int err = lfs_file_flush(lfs, file); if (err) { @@ -1155,23 +1209,28 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, 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->pos, &file->rblock, &file->roff); + if (!(file->flags & LFS_F_READING) || + file->off == lfs->cfg->block_size) { + int err = lfs_index_find(lfs, &file->cache, NULL, + file->head, file->size, + file->pos, &file->block, &file->off); if (err) { return err; } + + file->flags |= LFS_F_READING; } // 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, data, diff); + lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); + int err = lfs_cache_read(lfs, &file->cache, NULL, + file->block, file->off, data, diff); if (err) { return err; } file->pos += diff; - file->roff += diff; + file->off += diff; data += diff; nsize -= diff; } @@ -1188,7 +1247,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, return LFS_ERR_INVAL; } - if (file->rblock) { + if (file->flags & LFS_F_READING) { // drop any reads int err = lfs_file_flush(lfs, file); if (err) { @@ -1202,44 +1261,45 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, while (nsize > 0) { // check if we need a new block - if (!file->wblock || file->woff == lfs->cfg->block_size) { - if (!file->wblock) { + if (!(file->flags & LFS_F_WRITING) || + file->off == lfs->cfg->block_size) { + if (!(file->flags & LFS_F_WRITING)) { // find out which block we're extending from - int err = lfs_index_find(lfs, file->head, file->size, - file->pos, &file->wblock, &file->woff); + int err = lfs_index_find(lfs, &file->cache, NULL, + file->head, file->size, + file->pos, &file->block, &file->off); if (err) { return err; } + + // mark cache as dirty since we may have read data into it + file->cache.off = -1; + file->flags |= LFS_F_WRITING; } // extend file with new blocks - int err = lfs_index_extend(lfs, file->wblock, file->pos, - &file->wblock, &file->woff); + int err = lfs_index_extend(lfs, &lfs->rcache, &file->cache, + file->block, file->pos, + &file->block, &file->off); 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, data, diff); + lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); + int err = lfs_cache_prog(lfs, &file->cache, + file->block, file->off, data, diff); if (err) { return err; } file->pos += diff; - file->woff += diff; + file->off += diff; data += diff; nsize -= diff; } - if (file->flags & LFS_O_SYNC) { - int err = lfs_file_sync(lfs, file); - if (err) { - return err; - } - } - return size; } @@ -1303,7 +1363,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { info->size = entry.d.u.file.size; } - err = lfs_bd_read(lfs, cwd.pair[0], entry.off + sizeof(entry.d), + err = lfs_read(lfs, cwd.pair[0], entry.off + sizeof(entry.d), info->name, entry.d.len - sizeof(entry.d)); if (err) { return err; @@ -1593,7 +1653,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { lfs_superblock_t superblock; err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); if (!err) { - err = lfs_bd_read(lfs, dir.pair[0], + err = lfs_read(lfs, dir.pair[0], sizeof(dir.d), &superblock.d, sizeof(superblock.d)); lfs->root[0] = superblock.d.root[0]; @@ -1643,7 +1703,7 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { // iterate over contents while ((0x7fffffff & dir.d.size) >= dir.off + sizeof(entry.d)) { - int err = lfs_bd_read(lfs, dir.pair[0], dir.off, + int err = lfs_read(lfs, dir.pair[0], dir.off, &entry.d, sizeof(entry.d)); if (err) { return err; @@ -1651,7 +1711,7 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { dir.off += entry.d.len; if ((0xf & entry.d.type) == LFS_TYPE_REG) { - int err = lfs_index_traverse(lfs, + int err = lfs_index_traverse(lfs, &lfs->rcache, NULL, entry.d.u.file.head, entry.d.u.file.size, cb, data); if (err) { return err; @@ -1669,15 +1729,17 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { // iterate over any open files for (lfs_file_t *f = lfs->files; f; f = f->next) { - if (f->flags & LFS_O_DIRTY) { - int err = lfs_index_traverse(lfs, f->head, f->size, cb, data); + if (f->flags & LFS_F_DIRTY) { + int err = lfs_index_traverse(lfs, &lfs->rcache, &f->cache, + f->head, f->size, cb, data); if (err) { return err; } } - if (f->wblock) { - int err = lfs_index_traverse(lfs, f->wblock, f->pos, cb, data); + if (f->flags & LFS_F_WRITING) { + int err = lfs_index_traverse(lfs, &lfs->rcache, &f->cache, + f->block, f->pos, cb, data); if (err) { return err; } diff --git a/lfs.h b/lfs.h index a1017f5da41..c7a975933f1 100644 --- a/lfs.h +++ b/lfs.h @@ -47,15 +47,19 @@ enum lfs_type { }; enum lfs_open_flags { - LFS_O_RDONLY = 0, - LFS_O_WRONLY = 1, - LFS_O_RDWR = 2, - LFS_O_CREAT = 0x020, - LFS_O_EXCL = 0x040, - LFS_O_TRUNC = 0x080, - LFS_O_APPEND = 0x100, - LFS_O_SYNC = 0x200, - LFS_O_DIRTY = 0x10000, + // open flags + LFS_O_RDONLY = 1, + LFS_O_WRONLY = 2, + LFS_O_RDWR = 3, + LFS_O_CREAT = 0x0100, + LFS_O_EXCL = 0x0200, + LFS_O_TRUNC = 0x0400, + LFS_O_APPEND = 0x0800, + + // internally used flags + LFS_F_DIRTY = 0x10000, + LFS_F_WRITING = 0x20000, + LFS_F_READING = 0x40000, }; enum lfs_whence_flags { @@ -112,6 +116,10 @@ struct lfs_config { // Optional, statically allocated lookahead buffer. // Must be 1 bit per lookahead block. void *lookahead_buffer; + + // Optional, statically allocated buffer for files. Must be program sized. + // If enabled, only one file may be opened at a time + void *file_buffer; }; // File info structure @@ -144,21 +152,25 @@ typedef struct lfs_entry { } d; } lfs_entry_t; +typedef struct lfs_cache { + lfs_block_t block; + lfs_off_t off; + uint8_t *buffer; +} lfs_cache_t; + typedef struct lfs_file { struct lfs_file *next; lfs_block_t pair[2]; - lfs_off_t off; + lfs_off_t poff; + lfs_block_t head; lfs_size_t size; uint32_t flags; lfs_off_t pos; - - lfs_block_t wblock; - lfs_off_t woff; - - lfs_block_t rblock; - lfs_off_t roff; + lfs_block_t block; + lfs_off_t off; + lfs_cache_t cache; } lfs_file_t; typedef struct lfs_dir { @@ -189,6 +201,12 @@ typedef struct lfs_superblock { } d; } lfs_superblock_t; +typedef struct lfs_free { + lfs_block_t start; + lfs_block_t off; + uint32_t *lookahead; +} lfs_free_t; + // littlefs type typedef struct lfs { const struct lfs_config *cfg; @@ -198,17 +216,10 @@ typedef struct lfs { lfs_dir_t *scratch; lfs_file_t *files; - struct { - lfs_block_t block; - lfs_off_t off; - uint8_t *buffer; - } rcache, pcache; - - struct { - lfs_block_t start; - lfs_block_t off; - uint32_t *lookahead; - } free; + lfs_cache_t rcache; + lfs_cache_t pcache; + + lfs_free_t free; } lfs_t;