mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Fixed relocation bug when a file is closed with lingering caches
This bug required larger cache sizes to notice, since block errors usually get detected in the early stages of writing to files. Since the fix here requires both lfs_file_write and lfs_file_flush relocate file blocks, the relocation logic was moved out into a seperate function.
This commit is contained in:
		
							
								
								
									
										93
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										93
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -1183,6 +1183,50 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { | |||||||
|     return err; |     return err; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { | ||||||
|  | relocate: | ||||||
|  |     LFS_DEBUG("Bad block at %d", file->block); | ||||||
|  |  | ||||||
|  |     // just relocate what exists into new block | ||||||
|  |     lfs_block_t nblock; | ||||||
|  |     int err = lfs_alloc(lfs, &nblock); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // either read from dirty cache or disk | ||||||
|  |     for (lfs_off_t i = 0; i < file->off; i++) { | ||||||
|  |         uint8_t data; | ||||||
|  |         if (file->cache.block == file->block && i >= file->cache.off) { | ||||||
|  |             data = file->cache.buffer[i - file->cache.off]; | ||||||
|  |         } else { | ||||||
|  |             // just read from disk | ||||||
|  |             err = lfs_bd_read(lfs, file->block, i, &data, 1); | ||||||
|  |             if (err) { | ||||||
|  |                 return err; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, | ||||||
|  |                 nblock, i, &data, 1); | ||||||
|  |         if (err) { | ||||||
|  |             if (err == LFS_ERR_CORRUPT) { | ||||||
|  |                 goto relocate; | ||||||
|  |             } | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // copy over new state of file | ||||||
|  |     memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size); | ||||||
|  |     file->cache.block = lfs->pcache.block; | ||||||
|  |     file->cache.off = lfs->pcache.off; | ||||||
|  |     lfs->pcache.block = 0xffffffff; | ||||||
|  |  | ||||||
|  |     file->block = nblock; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| 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_READING) { |     if (file->flags & LFS_F_READING) { | ||||||
|         // just drop read cache |         // just drop read cache | ||||||
| @@ -1225,11 +1269,23 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // write out what we have |         // write out what we have | ||||||
|  |         while (true) { | ||||||
|             int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache); |             int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache); | ||||||
|             if (err) { |             if (err) { | ||||||
|  |                 if (err == LFS_ERR_CORRUPT) { | ||||||
|  |                     goto relocate; | ||||||
|  |                 } | ||||||
|                 return err; |                 return err; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             break; | ||||||
|  | relocate: | ||||||
|  |             err = lfs_file_relocate(lfs, file); | ||||||
|  |             if (err) { | ||||||
|  |                 return err; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // actual file updates |         // actual file updates | ||||||
|         file->head = file->block; |         file->head = file->block; | ||||||
|         file->size = file->pos; |         file->size = file->pos; | ||||||
| @@ -1396,45 +1452,10 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, | |||||||
|  |  | ||||||
|             break; |             break; | ||||||
| relocate: | relocate: | ||||||
|             LFS_DEBUG("Bad block at %d", file->block); |             err = lfs_file_relocate(lfs, file); | ||||||
|  |  | ||||||
|             // just relocate what exists into new block |  | ||||||
|             lfs_block_t nblock; |  | ||||||
|             err = lfs_alloc(lfs, &nblock); |  | ||||||
|             if (err) { |             if (err) { | ||||||
|                 return err; |                 return err; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // either read from dirty cache or disk |  | ||||||
|             for (lfs_off_t i = 0; i < file->off; i++) { |  | ||||||
|                 uint8_t data; |  | ||||||
|                 if (file->cache.block == file->block && i >= file->cache.off) { |  | ||||||
|                     data = file->cache.buffer[i - file->cache.off]; |  | ||||||
|                 } else { |  | ||||||
|                     // just read from disk |  | ||||||
|                     err = lfs_bd_read(lfs, file->block, i, &data, 1); |  | ||||||
|                     if (err) { |  | ||||||
|                         return err; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, |  | ||||||
|                         nblock, i, &data, 1); |  | ||||||
|                 if (err) { |  | ||||||
|                     if (err == LFS_ERR_CORRUPT) { |  | ||||||
|                         goto relocate; |  | ||||||
|                     } |  | ||||||
|                     return err; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             // copy over new state of file |  | ||||||
|             memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size); |  | ||||||
|             file->cache.block = lfs->pcache.block; |  | ||||||
|             file->cache.off = lfs->pcache.off; |  | ||||||
|             lfs->pcache.block = 0xffffffff; |  | ||||||
|  |  | ||||||
|             file->block = nblock; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         file->pos += diff; |         file->pos += diff; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user