Added proper handling of orphans
Unfortunately, threading all dir blocks in a linked-list did not come without problems. While it's possible to atomically add a dir to the linked list (by adding the new dir into the linked-list position immediately after it's parent, requiring only one atomic update to the parent block), it is not easy to make sure the linked-list is in a state that always allows atomic removal of dirs. The simple solution is to allow this non-atomic removal, with an additional step to remove any orphans that could have been created by a power-loss. This deorphan step is only run if the normal allocator has failed.
This commit is contained in:
+14
-18
@@ -14,6 +14,8 @@
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
// Block device emulated on existing filesystem
|
||||
@@ -76,12 +78,10 @@ int lfs_emubd_read(lfs_emubd_t *emu, lfs_block_t block,
|
||||
uint8_t *data = buffer;
|
||||
|
||||
// Check if read is valid
|
||||
if (!(off % emu->info.read_size == 0 &&
|
||||
size % emu->info.read_size == 0 &&
|
||||
((uint64_t)block*emu->info.erase_size + off + size
|
||||
< emu->info.total_size))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
assert(off % emu->info.read_size == 0);
|
||||
assert(size % emu->info.read_size == 0);
|
||||
assert((uint64_t)block*emu->info.erase_size + off + size
|
||||
< emu->info.total_size);
|
||||
|
||||
// Zero out buffer for debugging
|
||||
memset(data, 0, size);
|
||||
@@ -128,12 +128,10 @@ int lfs_emubd_prog(lfs_emubd_t *emu, lfs_block_t block,
|
||||
const uint8_t *data = buffer;
|
||||
|
||||
// Check if write is valid
|
||||
if (!(off % emu->info.prog_size == 0 &&
|
||||
size % emu->info.prog_size == 0 &&
|
||||
((uint64_t)block*emu->info.erase_size + off + size
|
||||
< emu->info.total_size))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
assert(off % emu->info.prog_size == 0);
|
||||
assert(size % emu->info.prog_size == 0);
|
||||
assert((uint64_t)block*emu->info.erase_size + off + size
|
||||
< emu->info.total_size);
|
||||
|
||||
// Iterate over blocks until enough data is read
|
||||
while (size > 0) {
|
||||
@@ -177,12 +175,10 @@ int lfs_emubd_erase(lfs_emubd_t *emu, lfs_block_t block,
|
||||
lfs_off_t off, lfs_size_t size) {
|
||||
|
||||
// Check if erase is valid
|
||||
if (!(off % emu->info.erase_size == 0 &&
|
||||
size % emu->info.erase_size == 0 &&
|
||||
((uint64_t)block*emu->info.erase_size + off + size
|
||||
< emu->info.total_size))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
assert(off % emu->info.erase_size == 0);
|
||||
assert(size % emu->info.erase_size == 0);
|
||||
assert((uint64_t)block*emu->info.erase_size + off + size
|
||||
< emu->info.total_size);
|
||||
|
||||
// Iterate and erase blocks
|
||||
while (size > 0) {
|
||||
|
||||
Reference in New Issue
Block a user