mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Introduced cache_size as alternative to hardware read/write sizes
The introduction of an explicit cache_size configuration allows customization of the cache buffers independently from the hardware read/write sizes. This has been one of littlefs's main handicaps. Without a distinction between cache units and hardware limitations, littlefs isn't able to read or program _less_ than the cache size. This leads to the counter-intuitive case where larger cache sizes can actually be harmful, since larger read/prog sizes require sending more data over the bus if we're only accessing a small set of data (for example the CTZ skip-list traversal). This is compounded with metadata logging, since a large program size limits the number of commits we can write out in a single metadata block. It really doesn't make sense to link program size + cache size here. With a separate cache_size configuration, we can be much smarter about what we actually read/write from disk. This also simplifies cache handling a bit. Before there were two possible cache sizes, but these were rarely used. Note that the cache_size is NOT written to the superblock and can be freely changed without breaking backwards compatibility.
This commit is contained in:
		| @@ -18,8 +18,8 @@ script: | |||||||
|   - make test QUIET=1 |   - make test QUIET=1 | ||||||
|  |  | ||||||
|   # run tests with a few different configurations |   # run tests with a few different configurations | ||||||
|   - make test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=1      -DLFS_PROG_SIZE=1" |   - make test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=1      -DLFS_CACHE_SIZE=4" | ||||||
|   - make test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=512    -DLFS_PROG_SIZE=512" |   - make test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=512    -DLFS_CACHE_SIZE=512" | ||||||
|   - make test QUIET=1 CFLAGS+="-DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD=2048" |   - make test QUIET=1 CFLAGS+="-DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD=2048" | ||||||
|  |  | ||||||
|   - make clean test QUIET=1 CFLAGS+="-DLFS_INLINE_MAX=0" |   - make clean test QUIET=1 CFLAGS+="-DLFS_INLINE_MAX=0" | ||||||
|   | |||||||
							
								
								
									
										179
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										179
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -20,18 +20,19 @@ | |||||||
|  |  | ||||||
|  |  | ||||||
| /// Caching block device operations /// | /// Caching block device operations /// | ||||||
| static int lfs_cache_read(lfs_t *lfs, lfs_cache_t *rcache, | static int lfs_cache_read(lfs_t *lfs, | ||||||
|         const lfs_cache_t *pcache, lfs_block_t block, |         const lfs_cache_t *pcache, lfs_cache_t *rcache, bool store, | ||||||
|         lfs_off_t off, void *buffer, lfs_size_t size) { |         lfs_block_t block, lfs_off_t off, | ||||||
|  |         void *buffer, lfs_size_t size) { | ||||||
|     uint8_t *data = buffer; |     uint8_t *data = buffer; | ||||||
|     LFS_ASSERT(block != 0xffffffff); |     LFS_ASSERT(block != 0xffffffff); | ||||||
|  |  | ||||||
|     while (size > 0) { |     while (size > 0) { | ||||||
|         if (pcache && block == pcache->block && off >= pcache->off && |         if (pcache && block == pcache->block && | ||||||
|                 off < pcache->off + lfs->cfg->prog_size) { |                 off >= pcache->off && | ||||||
|  |                 off < pcache->off + pcache->size) { | ||||||
|             // is already in pcache? |             // is already in pcache? | ||||||
|             lfs_size_t diff = lfs_min(size, |             lfs_size_t diff = lfs_min(size, pcache->size - (off-pcache->off)); | ||||||
|                     lfs->cfg->prog_size - (off-pcache->off)); |  | ||||||
|             memcpy(data, &pcache->buffer[off-pcache->off], diff); |             memcpy(data, &pcache->buffer[off-pcache->off], diff); | ||||||
|  |  | ||||||
|             data += diff; |             data += diff; | ||||||
| @@ -40,11 +41,14 @@ static int lfs_cache_read(lfs_t *lfs, lfs_cache_t *rcache, | |||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (block == rcache->block && off >= rcache->off && |         if (block == rcache->block && | ||||||
|                 off < rcache->off + lfs->cfg->read_size) { |                 off >= rcache->off && | ||||||
|  |                 off < rcache->off + rcache->size) { | ||||||
|             // is already in rcache? |             // is already in rcache? | ||||||
|             lfs_size_t diff = lfs_min(size, |             lfs_size_t diff = lfs_min(size, rcache->size - (off-rcache->off)); | ||||||
|                     lfs->cfg->read_size - (off-rcache->off)); |             if (pcache && block == pcache->block) { | ||||||
|  |                 diff = lfs_min(diff, pcache->off - off); | ||||||
|  |             } | ||||||
|             memcpy(data, &rcache->buffer[off-rcache->off], diff); |             memcpy(data, &rcache->buffer[off-rcache->off], diff); | ||||||
|  |  | ||||||
|             data += diff; |             data += diff; | ||||||
| @@ -53,7 +57,8 @@ static int lfs_cache_read(lfs_t *lfs, lfs_cache_t *rcache, | |||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (off % lfs->cfg->read_size == 0 && size >= lfs->cfg->read_size) { |         if (!store && off % lfs->cfg->read_size == 0 && | ||||||
|  |                 size >= lfs->cfg->read_size) { | ||||||
|             // bypass cache? |             // bypass cache? | ||||||
|             lfs_size_t diff = size - (size % lfs->cfg->read_size); |             lfs_size_t diff = size - (size % lfs->cfg->read_size); | ||||||
|             int err = lfs->cfg->read(lfs->cfg, block, off, data, diff); |             int err = lfs->cfg->read(lfs->cfg, block, off, data, diff); | ||||||
| @@ -69,10 +74,12 @@ static int lfs_cache_read(lfs_t *lfs, lfs_cache_t *rcache, | |||||||
|  |  | ||||||
|         // load to cache, first condition can no longer fail |         // load to cache, first condition can no longer fail | ||||||
|         LFS_ASSERT(block < lfs->cfg->block_count); |         LFS_ASSERT(block < lfs->cfg->block_count); | ||||||
|  |         lfs_size_t size = store ? lfs->cfg->cache_size : lfs->cfg->prog_size; | ||||||
|         rcache->block = block; |         rcache->block = block; | ||||||
|         rcache->off = off - (off % lfs->cfg->read_size); |         rcache->off = lfs_aligndown(off, size); | ||||||
|  |         rcache->size = size; | ||||||
|         int err = lfs->cfg->read(lfs->cfg, rcache->block, |         int err = lfs->cfg->read(lfs->cfg, rcache->block, | ||||||
|                 rcache->off, rcache->buffer, lfs->cfg->read_size); |                 rcache->off, rcache->buffer, size); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
| @@ -81,14 +88,15 @@ static int lfs_cache_read(lfs_t *lfs, lfs_cache_t *rcache, | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_cache_cmp(lfs_t *lfs, lfs_cache_t *rcache, | static int lfs_cache_cmp(lfs_t *lfs, | ||||||
|         const lfs_cache_t *pcache, lfs_block_t block, |         const lfs_cache_t *pcache, lfs_cache_t *rcache, | ||||||
|         lfs_off_t off, const void *buffer, lfs_size_t size) { |         lfs_block_t block, lfs_off_t off, | ||||||
|  |         const void *buffer, lfs_size_t size) { | ||||||
|     const uint8_t *data = buffer; |     const uint8_t *data = buffer; | ||||||
|  |  | ||||||
|     for (lfs_off_t i = 0; i < size; i++) { |     for (lfs_off_t i = 0; i < size; i++) { | ||||||
|         uint8_t c; |         uint8_t c; | ||||||
|         int err = lfs_cache_read(lfs, rcache, pcache, |         int err = lfs_cache_read(lfs, pcache, rcache, true, | ||||||
|                 block, off+i, &c, 1); |                 block, off+i, &c, 1); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
| @@ -102,12 +110,12 @@ static int lfs_cache_cmp(lfs_t *lfs, lfs_cache_t *rcache, | |||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_cache_crc(lfs_t *lfs, lfs_cache_t *rcache, | static int lfs_cache_crc(lfs_t *lfs, | ||||||
|         const lfs_cache_t *pcache, lfs_block_t block, |         const lfs_cache_t *pcache, lfs_cache_t *rcache, | ||||||
|         lfs_off_t off, lfs_size_t size, uint32_t *crc) { |         lfs_block_t block, lfs_off_t off, lfs_size_t size, uint32_t *crc) { | ||||||
|     for (lfs_off_t i = 0; i < size; i++) { |     for (lfs_off_t i = 0; i < size; i++) { | ||||||
|         uint8_t c; |         uint8_t c; | ||||||
|         int err = lfs_cache_read(lfs, rcache, pcache, |         int err = lfs_cache_read(lfs, pcache, rcache, true, | ||||||
|                 block, off+i, &c, 1); |                 block, off+i, &c, 1); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
| @@ -120,18 +128,21 @@ static int lfs_cache_crc(lfs_t *lfs, lfs_cache_t *rcache, | |||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_cache_flush(lfs_t *lfs, | static int lfs_cache_flush(lfs_t *lfs, | ||||||
|         lfs_cache_t *pcache, lfs_cache_t *rcache) { |         lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) { | ||||||
|     if (pcache->block != 0xffffffff) { |     if (pcache->block != 0xffffffff) { | ||||||
|         LFS_ASSERT(pcache->block < lfs->cfg->block_count); |         LFS_ASSERT(pcache->block < lfs->cfg->block_count); | ||||||
|  |         lfs_size_t diff = lfs_alignup(pcache->size, lfs->cfg->prog_size); | ||||||
|         int err = lfs->cfg->prog(lfs->cfg, pcache->block, |         int err = lfs->cfg->prog(lfs->cfg, pcache->block, | ||||||
|                 pcache->off, pcache->buffer, lfs->cfg->prog_size); |                 pcache->off, pcache->buffer, diff); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (rcache) { |         if (validate) { | ||||||
|             int res = lfs_cache_cmp(lfs, rcache, NULL, pcache->block, |             // check data on disk | ||||||
|                     pcache->off, pcache->buffer, lfs->cfg->prog_size); |             rcache->block = 0xffffffff; | ||||||
|  |             int res = lfs_cache_cmp(lfs, NULL, rcache, pcache->block, | ||||||
|  |                     pcache->off, pcache->buffer, diff); | ||||||
|             if (res < 0) { |             if (res < 0) { | ||||||
|                 return res; |                 return res; | ||||||
|             } |             } | ||||||
| @@ -147,28 +158,31 @@ static int lfs_cache_flush(lfs_t *lfs, | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_cache_prog(lfs_t *lfs, lfs_cache_t *pcache, | static int lfs_cache_prog(lfs_t *lfs, | ||||||
|         lfs_cache_t *rcache, lfs_block_t block, |         lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate, | ||||||
|         lfs_off_t off, const void *buffer, lfs_size_t size) { |         lfs_block_t block, lfs_off_t off, | ||||||
|  |         const void *buffer, lfs_size_t size) { | ||||||
|     const uint8_t *data = buffer; |     const uint8_t *data = buffer; | ||||||
|     LFS_ASSERT(block != 0xffffffff); |     LFS_ASSERT(block != 0xffffffff); | ||||||
|     LFS_ASSERT(off + size <= lfs->cfg->block_size); |     LFS_ASSERT(off + size <= lfs->cfg->block_size); | ||||||
|  |  | ||||||
|     while (size > 0) { |     while (size > 0) { | ||||||
|         if (block == pcache->block && off >= pcache->off && |         if (block == pcache->block && | ||||||
|                 off < pcache->off + lfs->cfg->prog_size) { |                 off >= pcache->off && | ||||||
|             // is already in pcache? |                 off < pcache->off + lfs->cfg->cache_size) { | ||||||
|  |             // already fits in pcache? | ||||||
|             lfs_size_t diff = lfs_min(size, |             lfs_size_t diff = lfs_min(size, | ||||||
|                     lfs->cfg->prog_size - (off-pcache->off)); |                     lfs->cfg->cache_size - (off-pcache->off)); | ||||||
|             memcpy(&pcache->buffer[off-pcache->off], data, diff); |             memcpy(&pcache->buffer[off-pcache->off], data, diff); | ||||||
|  |  | ||||||
|             data += diff; |             data += diff; | ||||||
|             off += diff; |             off += diff; | ||||||
|             size -= diff; |             size -= diff; | ||||||
|  |  | ||||||
|             if (off % lfs->cfg->prog_size == 0) { |             pcache->size = off - pcache->off; | ||||||
|  |             if (pcache->size == lfs->cfg->cache_size) { | ||||||
|                 // eagerly flush out pcache if we fill up |                 // eagerly flush out pcache if we fill up | ||||||
|                 int err = lfs_cache_flush(lfs, pcache, rcache); |                 int err = lfs_cache_flush(lfs, pcache, rcache, validate); | ||||||
|                 if (err) { |                 if (err) { | ||||||
|                     return err; |                     return err; | ||||||
|                 } |                 } | ||||||
| @@ -181,37 +195,10 @@ static int lfs_cache_prog(lfs_t *lfs, lfs_cache_t *pcache, | |||||||
|         // entire block or manually flushing the pcache |         // entire block or manually flushing the pcache | ||||||
|         LFS_ASSERT(pcache->block == 0xffffffff); |         LFS_ASSERT(pcache->block == 0xffffffff); | ||||||
|  |  | ||||||
|         if (off % lfs->cfg->prog_size == 0 && |  | ||||||
|                 size >= lfs->cfg->prog_size) { |  | ||||||
|             // bypass pcache? |  | ||||||
|             LFS_ASSERT(block < lfs->cfg->block_count); |  | ||||||
|             lfs_size_t diff = size - (size % lfs->cfg->prog_size); |  | ||||||
|             int err = lfs->cfg->prog(lfs->cfg, block, off, data, diff); |  | ||||||
|             if (err) { |  | ||||||
|                 return err; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (rcache) { |  | ||||||
|                 int res = lfs_cache_cmp(lfs, rcache, NULL, |  | ||||||
|                         block, off, data, diff); |  | ||||||
|                 if (res < 0) { |  | ||||||
|                     return res; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if (!res) { |  | ||||||
|                     return LFS_ERR_CORRUPT; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             data += diff; |  | ||||||
|             off += diff; |  | ||||||
|             size -= diff; |  | ||||||
|             continue; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // prepare pcache, first condition can no longer fail |         // prepare pcache, first condition can no longer fail | ||||||
|         pcache->block = block; |         pcache->block = block; | ||||||
|         pcache->off = off - (off % lfs->cfg->prog_size); |         pcache->off = lfs_aligndown(off, lfs->cfg->prog_size); | ||||||
|  |         pcache->size = 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| @@ -221,24 +208,24 @@ static int lfs_cache_prog(lfs_t *lfs, lfs_cache_t *pcache, | |||||||
| /// General lfs block device operations /// | /// General lfs block device operations /// | ||||||
| static int lfs_bd_read(lfs_t *lfs, lfs_block_t block, | static int lfs_bd_read(lfs_t *lfs, lfs_block_t block, | ||||||
|         lfs_off_t off, void *buffer, lfs_size_t size) { |         lfs_off_t off, void *buffer, lfs_size_t size) { | ||||||
|     return lfs_cache_read(lfs, &lfs->rcache, &lfs->pcache, |     return lfs_cache_read(lfs, &lfs->pcache, &lfs->rcache, true, | ||||||
|             block, off, buffer, size); |             block, off, buffer, size); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_bd_prog(lfs_t *lfs, lfs_block_t block, | static int lfs_bd_prog(lfs_t *lfs, lfs_block_t block, | ||||||
|         lfs_off_t off, const void *buffer, lfs_size_t size) { |         lfs_off_t off, const void *buffer, lfs_size_t size) { | ||||||
|     return lfs_cache_prog(lfs, &lfs->pcache, NULL, |     return lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, false, | ||||||
|             block, off, buffer, size); |             block, off, buffer, size); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block, | static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block, | ||||||
|         lfs_off_t off, const void *buffer, lfs_size_t size) { |         lfs_off_t off, const void *buffer, lfs_size_t size) { | ||||||
|     return lfs_cache_cmp(lfs, &lfs->rcache, NULL, block, off, buffer, size); |     return lfs_cache_cmp(lfs, NULL, &lfs->rcache, block, off, buffer, size); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_bd_crc(lfs_t *lfs, lfs_block_t block, | static int lfs_bd_crc(lfs_t *lfs, lfs_block_t block, | ||||||
|         lfs_off_t off, lfs_size_t size, uint32_t *crc) { |         lfs_off_t off, lfs_size_t size, uint32_t *crc) { | ||||||
|     return lfs_cache_crc(lfs, &lfs->rcache, NULL, block, off, size, crc); |     return lfs_cache_crc(lfs, NULL, &lfs->rcache, block, off, size, crc); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) { | static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) { | ||||||
| @@ -249,7 +236,7 @@ static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) { | |||||||
| static int lfs_bd_sync(lfs_t *lfs) { | static int lfs_bd_sync(lfs_t *lfs) { | ||||||
|     lfs->rcache.block = 0xffffffff; |     lfs->rcache.block = 0xffffffff; | ||||||
|  |  | ||||||
|     int err = lfs_cache_flush(lfs, &lfs->pcache, NULL); |     int err = lfs_cache_flush(lfs, &lfs->pcache, &lfs->rcache, false); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| @@ -1658,7 +1645,8 @@ static int lfs_ctzfind(lfs_t *lfs, | |||||||
|                 lfs_npw2(current-target+1) - 1, |                 lfs_npw2(current-target+1) - 1, | ||||||
|                 lfs_ctz(current)); |                 lfs_ctz(current)); | ||||||
|  |  | ||||||
|         int err = lfs_cache_read(lfs, rcache, pcache, head, 4*skip, &head, 4); |         int err = lfs_cache_read(lfs, pcache, rcache, false, | ||||||
|  |                 head, 4*skip, &head, 4); | ||||||
|         head = lfs_fromle32(head); |         head = lfs_fromle32(head); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
| @@ -1709,13 +1697,13 @@ static int lfs_ctzextend(lfs_t *lfs, | |||||||
|             if (size != lfs->cfg->block_size) { |             if (size != lfs->cfg->block_size) { | ||||||
|                 for (lfs_off_t i = 0; i < size; i++) { |                 for (lfs_off_t i = 0; i < size; i++) { | ||||||
|                     uint8_t data; |                     uint8_t data; | ||||||
|                     err = lfs_cache_read(lfs, rcache, NULL, |                     err = lfs_cache_read(lfs, NULL, rcache, true, | ||||||
|                             head, i, &data, 1); |                             head, i, &data, 1); | ||||||
|                     if (err) { |                     if (err) { | ||||||
|                         return err; |                         return err; | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     err = lfs_cache_prog(lfs, pcache, rcache, |                     err = lfs_cache_prog(lfs, pcache, rcache, true, | ||||||
|                             nblock, i, &data, 1); |                             nblock, i, &data, 1); | ||||||
|                     if (err) { |                     if (err) { | ||||||
|                         if (err == LFS_ERR_CORRUPT) { |                         if (err == LFS_ERR_CORRUPT) { | ||||||
| @@ -1736,7 +1724,7 @@ static int lfs_ctzextend(lfs_t *lfs, | |||||||
|  |  | ||||||
|             for (lfs_off_t i = 0; i < skips; i++) { |             for (lfs_off_t i = 0; i < skips; i++) { | ||||||
|                 head = lfs_tole32(head); |                 head = lfs_tole32(head); | ||||||
|                 err = lfs_cache_prog(lfs, pcache, rcache, |                 err = lfs_cache_prog(lfs, pcache, rcache, true, | ||||||
|                         nblock, 4*i, &head, 4); |                         nblock, 4*i, &head, 4); | ||||||
|                 head = lfs_fromle32(head); |                 head = lfs_fromle32(head); | ||||||
|                 if (err) { |                 if (err) { | ||||||
| @@ -1747,7 +1735,7 @@ static int lfs_ctzextend(lfs_t *lfs, | |||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 if (i != skips-1) { |                 if (i != skips-1) { | ||||||
|                     err = lfs_cache_read(lfs, rcache, NULL, |                     err = lfs_cache_read(lfs, NULL, rcache, false, | ||||||
|                             head, 4*i, &head, 4); |                             head, 4*i, &head, 4); | ||||||
|                     head = lfs_fromle32(head); |                     head = lfs_fromle32(head); | ||||||
|                     if (err) { |                     if (err) { | ||||||
| @@ -1793,7 +1781,8 @@ static int lfs_ctztraverse(lfs_t *lfs, | |||||||
|  |  | ||||||
|         lfs_block_t heads[2]; |         lfs_block_t heads[2]; | ||||||
|         int count = 2 - (index & 1); |         int count = 2 - (index & 1); | ||||||
|         err = lfs_cache_read(lfs, rcache, pcache, head, 0, &heads, count*4); |         err = lfs_cache_read(lfs, pcache, rcache, false, | ||||||
|  |                 head, 0, &heads, count*4); | ||||||
|         heads[0] = lfs_fromle32(heads[0]); |         heads[0] = lfs_fromle32(heads[0]); | ||||||
|         heads[1] = lfs_fromle32(heads[1]); |         heads[1] = lfs_fromle32(heads[1]); | ||||||
|         if (err) { |         if (err) { | ||||||
| @@ -1916,15 +1905,8 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | |||||||
|     file->cache.block = 0xffffffff; |     file->cache.block = 0xffffffff; | ||||||
|     if (file->cfg->buffer) { |     if (file->cfg->buffer) { | ||||||
|         file->cache.buffer = file->cfg->buffer; |         file->cache.buffer = file->cfg->buffer; | ||||||
|     } else if ((file->flags & 3) == LFS_O_RDONLY) { |  | ||||||
|         // TODO cache_size |  | ||||||
|         file->cache.buffer = lfs_malloc(lfs->cfg->read_size); |  | ||||||
|         if (!file->cache.buffer) { |  | ||||||
|             err = LFS_ERR_NOMEM; |  | ||||||
|             goto cleanup; |  | ||||||
|         } |  | ||||||
|     } else { |     } else { | ||||||
|         file->cache.buffer = lfs_malloc(lfs->cfg->prog_size); |         file->cache.buffer = lfs_malloc(lfs->cfg->cache_size); | ||||||
|         if (!file->cache.buffer) { |         if (!file->cache.buffer) { | ||||||
|             err = LFS_ERR_NOMEM; |             err = LFS_ERR_NOMEM; | ||||||
|             goto cleanup; |             goto cleanup; | ||||||
| @@ -1938,6 +1920,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | |||||||
|         file->flags |= LFS_F_INLINE; |         file->flags |= LFS_F_INLINE; | ||||||
|         file->cache.block = file->ctz.head; |         file->cache.block = file->ctz.head; | ||||||
|         file->cache.off = 0; |         file->cache.off = 0; | ||||||
|  |         file->cache.size = lfs->cfg->cache_size; | ||||||
|  |  | ||||||
|         // don't always read (may be new/trunc file) |         // don't always read (may be new/trunc file) | ||||||
|         if (file->ctz.size > 0) { |         if (file->ctz.size > 0) { | ||||||
| @@ -2005,13 +1988,13 @@ static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { | |||||||
|         // either read from dirty cache or disk |         // either read from dirty cache or disk | ||||||
|         for (lfs_off_t i = 0; i < file->off; i++) { |         for (lfs_off_t i = 0; i < file->off; i++) { | ||||||
|             uint8_t data; |             uint8_t data; | ||||||
|             err = lfs_cache_read(lfs, &lfs->rcache, &file->cache, |             err = lfs_cache_read(lfs, &file->cache, &lfs->rcache, true, | ||||||
|                     file->block, i, &data, 1); |                     file->block, i, &data, 1); | ||||||
|             if (err) { |             if (err) { | ||||||
|                 return err; |                 return err; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, |             err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, true, | ||||||
|                     nblock, i, &data, 1); |                     nblock, i, &data, 1); | ||||||
|             if (err) { |             if (err) { | ||||||
|                 if (err == LFS_ERR_CORRUPT) { |                 if (err == LFS_ERR_CORRUPT) { | ||||||
| @@ -2022,9 +2005,10 @@ static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // copy over new state of file |         // copy over new state of file | ||||||
|         memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size); |         memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->cache_size); | ||||||
|         file->cache.block = lfs->pcache.block; |         file->cache.block = lfs->pcache.block; | ||||||
|         file->cache.off = lfs->pcache.off; |         file->cache.off = lfs->pcache.off; | ||||||
|  |         file->cache.size = lfs->pcache.size; | ||||||
|         lfs->pcache.block = 0xffffffff; |         lfs->pcache.block = 0xffffffff; | ||||||
|  |  | ||||||
|         file->block = nblock; |         file->block = nblock; | ||||||
| @@ -2077,7 +2061,8 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { | |||||||
|  |  | ||||||
|             // write out what we have |             // write out what we have | ||||||
|             while (true) { |             while (true) { | ||||||
|                 int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache); |                 int err = lfs_cache_flush(lfs, | ||||||
|  |                         &file->cache, &lfs->rcache, true); | ||||||
|                 if (err) { |                 if (err) { | ||||||
|                     if (err == LFS_ERR_CORRUPT) { |                     if (err == LFS_ERR_CORRUPT) { | ||||||
|                         goto relocate; |                         goto relocate; | ||||||
| @@ -2217,7 +2202,7 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, | |||||||
|  |  | ||||||
|         // read as much as we can in current block |         // read as much as we can in current block | ||||||
|         lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); |         lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); | ||||||
|         int err = lfs_cache_read(lfs, &file->cache, NULL, |         int err = lfs_cache_read(lfs, NULL, &file->cache, true, | ||||||
|                 file->block, file->off, data, diff); |                 file->block, file->off, data, diff); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
| @@ -2322,7 +2307,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, | |||||||
|         // program as much as we can in current block |         // program as much as we can in current block | ||||||
|         lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); |         lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); | ||||||
|         while (true) { |         while (true) { | ||||||
|             int err = lfs_cache_prog(lfs, &file->cache, &lfs->rcache, |             int err = lfs_cache_prog(lfs, &file->cache, &lfs->rcache, true, | ||||||
|                     file->block, file->off, data, diff); |                     file->block, file->off, data, diff); | ||||||
|             if (err) { |             if (err) { | ||||||
|                 if (err == LFS_ERR_CORRUPT) { |                 if (err == LFS_ERR_CORRUPT) { | ||||||
| @@ -2723,7 +2708,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|     if (lfs->cfg->read_buffer) { |     if (lfs->cfg->read_buffer) { | ||||||
|         lfs->rcache.buffer = lfs->cfg->read_buffer; |         lfs->rcache.buffer = lfs->cfg->read_buffer; | ||||||
|     } else { |     } else { | ||||||
|         lfs->rcache.buffer = lfs_malloc(lfs->cfg->read_size); |         lfs->rcache.buffer = lfs_malloc(lfs->cfg->cache_size); | ||||||
|         if (!lfs->rcache.buffer) { |         if (!lfs->rcache.buffer) { | ||||||
|             return LFS_ERR_NOMEM; |             return LFS_ERR_NOMEM; | ||||||
|         } |         } | ||||||
| @@ -2734,7 +2719,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|     if (lfs->cfg->prog_buffer) { |     if (lfs->cfg->prog_buffer) { | ||||||
|         lfs->pcache.buffer = lfs->cfg->prog_buffer; |         lfs->pcache.buffer = lfs->cfg->prog_buffer; | ||||||
|     } else { |     } else { | ||||||
|         lfs->pcache.buffer = lfs_malloc(lfs->cfg->prog_size); |         lfs->pcache.buffer = lfs_malloc(lfs->cfg->cache_size); | ||||||
|         if (!lfs->pcache.buffer) { |         if (!lfs->pcache.buffer) { | ||||||
|             return LFS_ERR_NOMEM; |             return LFS_ERR_NOMEM; | ||||||
|         } |         } | ||||||
| @@ -2752,9 +2737,11 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // check that program and read sizes are multiples of the block size |     // check that block size is a multiple of cache size is a multiple | ||||||
|     LFS_ASSERT(lfs->cfg->prog_size % lfs->cfg->read_size == 0); |     // of prog and read sizes | ||||||
|     LFS_ASSERT(lfs->cfg->block_size % lfs->cfg->prog_size == 0); |     LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->read_size == 0); | ||||||
|  |     LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->prog_size == 0); | ||||||
|  |     LFS_ASSERT(lfs->cfg->block_size % lfs->cfg->cache_size == 0); | ||||||
|  |  | ||||||
|     // check that the block size is large enough to fit ctz pointers |     // check that the block size is large enough to fit ctz pointers | ||||||
|     LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4)) |     LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4)) | ||||||
| @@ -2762,7 +2749,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|  |  | ||||||
|     // check that the size limits are sane |     // check that the size limits are sane | ||||||
|     LFS_ASSERT(lfs->cfg->inline_size <= LFS_INLINE_MAX); |     LFS_ASSERT(lfs->cfg->inline_size <= LFS_INLINE_MAX); | ||||||
|     LFS_ASSERT(lfs->cfg->inline_size <= lfs->cfg->read_size); |     LFS_ASSERT(lfs->cfg->inline_size <= lfs->cfg->read_size); // TODO  | ||||||
|     lfs->inline_size = lfs->cfg->inline_size; |     lfs->inline_size = lfs->cfg->inline_size; | ||||||
|     if (!lfs->inline_size) { |     if (!lfs->inline_size) { | ||||||
|         lfs->inline_size = lfs_min(LFS_INLINE_MAX, lfs->cfg->read_size); |         lfs->inline_size = lfs_min(LFS_INLINE_MAX, lfs->cfg->read_size); | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -177,21 +177,24 @@ struct lfs_config { | |||||||
|     // are propogated to the user. |     // are propogated to the user. | ||||||
|     int (*sync)(const struct lfs_config *c); |     int (*sync)(const struct lfs_config *c); | ||||||
|  |  | ||||||
|     // Minimum size of a block read. This determines the size of read buffers. |     // Minimum size of a block read. All read operations will be a | ||||||
|     // This may be larger than the physical read size to improve performance |     // multiple of this value. | ||||||
|     // by caching more of the block device. |  | ||||||
|     lfs_size_t read_size; |     lfs_size_t read_size; | ||||||
|  |  | ||||||
|     // Minimum size of a block program. This determines the size of program |     // Minimum size of a block program. All program operations will be a | ||||||
|     // buffers. This may be larger than the physical program size to improve |     // multiple of this value. | ||||||
|     // performance by caching more of the block device. |  | ||||||
|     // Must be a multiple of the read size. |  | ||||||
|     lfs_size_t prog_size; |     lfs_size_t prog_size; | ||||||
|  |  | ||||||
|  |     // Size of block caches. Each cache buffers a portion of a block in RAM. | ||||||
|  |     // This determines the size of the read cache, the program cache, and a | ||||||
|  |     // cache per file. Larger caches can improve performance by storing more | ||||||
|  |     // data. Must be a multiple of the read and program sizes. | ||||||
|  |     lfs_size_t cache_size; | ||||||
|  |  | ||||||
|     // Size of an erasable block. This does not impact ram consumption and |     // Size of an erasable block. This does not impact ram consumption and | ||||||
|     // may be larger than the physical erase size. However, this should be |     // may be larger than the physical erase size. However, this should be | ||||||
|     // kept small as each file currently takes up an entire block. |     // kept small as each file currently takes up an entire block. | ||||||
|     // Must be a multiple of the program size. |     // Must be a multiple of the read, program, and cache sizes. | ||||||
|     lfs_size_t block_size; |     lfs_size_t block_size; | ||||||
|  |  | ||||||
|     // Number of erasable blocks on the device. |     // Number of erasable blocks on the device. | ||||||
| @@ -283,6 +286,7 @@ typedef struct lfs_mattr { | |||||||
| typedef struct lfs_cache { | typedef struct lfs_cache { | ||||||
|     lfs_block_t block; |     lfs_block_t block; | ||||||
|     lfs_off_t off; |     lfs_off_t off; | ||||||
|  |     lfs_size_t size; | ||||||
|     uint8_t *buffer; |     uint8_t *buffer; | ||||||
| } lfs_cache_t; | } lfs_cache_t; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -183,8 +183,12 @@ static inline uint16_t lfs_tole16(uint16_t a) { | |||||||
| } | } | ||||||
|  |  | ||||||
| // Align to nearest multiple of a size | // Align to nearest multiple of a size | ||||||
|  | static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { | ||||||
|  |     return a - (a % alignment); | ||||||
|  | } | ||||||
|  |  | ||||||
| static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { | static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { | ||||||
|     return (a + alignment-1) - ((a + alignment-1) % alignment); |     return lfs_aligndown(a + alignment-1, alignment); | ||||||
| } | } | ||||||
|  |  | ||||||
| // Calculate CRC-32 with polynomial = 0x04c11db7 | // Calculate CRC-32 with polynomial = 0x04c11db7 | ||||||
|   | |||||||
| @@ -66,7 +66,11 @@ uintmax_t test; | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifndef LFS_PROG_SIZE | #ifndef LFS_PROG_SIZE | ||||||
| #define LFS_PROG_SIZE 16 | #define LFS_PROG_SIZE LFS_READ_SIZE | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifndef LFS_CACHE_SIZE | ||||||
|  | #define LFS_CACHE_SIZE 64 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifndef LFS_BLOCK_SIZE | #ifndef LFS_BLOCK_SIZE | ||||||
| @@ -92,6 +96,7 @@ const struct lfs_config cfg = {{ | |||||||
|  |  | ||||||
|     .read_size   = LFS_READ_SIZE, |     .read_size   = LFS_READ_SIZE, | ||||||
|     .prog_size   = LFS_PROG_SIZE, |     .prog_size   = LFS_PROG_SIZE, | ||||||
|  |     .cache_size  = LFS_CACHE_SIZE, | ||||||
|     .block_size  = LFS_BLOCK_SIZE, |     .block_size  = LFS_BLOCK_SIZE, | ||||||
|     .block_count = LFS_BLOCK_COUNT, |     .block_count = LFS_BLOCK_COUNT, | ||||||
|     .lookahead   = LFS_LOOKAHEAD, |     .lookahead   = LFS_LOOKAHEAD, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user