Skip to content

Commit 1166416

Browse files
committed
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.
1 parent fe28ea0 commit 1166416

File tree

1 file changed

+60
-39
lines changed

1 file changed

+60
-39
lines changed

lfs.c

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,50 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
11831183
return err;
11841184
}
11851185

1186+
static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) {
1187+
relocate:
1188+
LFS_DEBUG("Bad block at %d", file->block);
1189+
1190+
// just relocate what exists into new block
1191+
lfs_block_t nblock;
1192+
int err = lfs_alloc(lfs, &nblock);
1193+
if (err) {
1194+
return err;
1195+
}
1196+
1197+
// either read from dirty cache or disk
1198+
for (lfs_off_t i = 0; i < file->off; i++) {
1199+
uint8_t data;
1200+
if (file->cache.block == file->block && i >= file->cache.off) {
1201+
data = file->cache.buffer[i - file->cache.off];
1202+
} else {
1203+
// just read from disk
1204+
err = lfs_bd_read(lfs, file->block, i, &data, 1);
1205+
if (err) {
1206+
return err;
1207+
}
1208+
}
1209+
1210+
err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache,
1211+
nblock, i, &data, 1);
1212+
if (err) {
1213+
if (err == LFS_ERR_CORRUPT) {
1214+
goto relocate;
1215+
}
1216+
return err;
1217+
}
1218+
}
1219+
1220+
// copy over new state of file
1221+
memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size);
1222+
file->cache.block = lfs->pcache.block;
1223+
file->cache.off = lfs->pcache.off;
1224+
lfs->pcache.block = 0xffffffff;
1225+
1226+
file->block = nblock;
1227+
return 0;
1228+
}
1229+
11861230
static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
11871231
if (file->flags & LFS_F_READING) {
11881232
// just drop read cache
@@ -1225,9 +1269,21 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
12251269
}
12261270

12271271
// write out what we have
1228-
int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache);
1229-
if (err) {
1230-
return err;
1272+
while (true) {
1273+
int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache);
1274+
if (err) {
1275+
if (err == LFS_ERR_CORRUPT) {
1276+
goto relocate;
1277+
}
1278+
return err;
1279+
}
1280+
1281+
break;
1282+
relocate:
1283+
err = lfs_file_relocate(lfs, file);
1284+
if (err) {
1285+
return err;
1286+
}
12311287
}
12321288

12331289
// actual file updates
@@ -1396,45 +1452,10 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
13961452

13971453
break;
13981454
relocate:
1399-
LFS_DEBUG("Bad block at %d", file->block);
1400-
1401-
// just relocate what exists into new block
1402-
lfs_block_t nblock;
1403-
err = lfs_alloc(lfs, &nblock);
1455+
err = lfs_file_relocate(lfs, file);
14041456
if (err) {
14051457
return err;
14061458
}
1407-
1408-
// either read from dirty cache or disk
1409-
for (lfs_off_t i = 0; i < file->off; i++) {
1410-
uint8_t data;
1411-
if (file->cache.block == file->block && i >= file->cache.off) {
1412-
data = file->cache.buffer[i - file->cache.off];
1413-
} else {
1414-
// just read from disk
1415-
err = lfs_bd_read(lfs, file->block, i, &data, 1);
1416-
if (err) {
1417-
return err;
1418-
}
1419-
}
1420-
1421-
err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache,
1422-
nblock, i, &data, 1);
1423-
if (err) {
1424-
if (err == LFS_ERR_CORRUPT) {
1425-
goto relocate;
1426-
}
1427-
return err;
1428-
}
1429-
}
1430-
1431-
// copy over new state of file
1432-
memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size);
1433-
file->cache.block = lfs->pcache.block;
1434-
file->cache.off = lfs->pcache.off;
1435-
lfs->pcache.block = 0xffffffff;
1436-
1437-
file->block = nblock;
14381459
}
14391460

14401461
file->pos += diff;

0 commit comments

Comments
 (0)