Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/littlefs-project/littlefs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/emubd
diff options
context:
space:
mode:
authorChristopher Haster <chaster@utexas.edu>2018-08-09 17:06:17 +0300
committerChristopher Haster <chaster@utexas.edu>2018-10-18 17:55:47 +0300
commit126ef8b07fc5f111fa2e3b4076441471dcd2e40e (patch)
tree19e99f8adb682f5480a0c018eef0da4b12f27fcf /emubd
parente4a0d586d5b38f092bd0c44ccece8659c6f4a025 (diff)
Added allocation randomization for dynamic wear-leveling
This implements the second step of full dynamic wear-leveling, block allocation randomization. This is the key part the uniformly distributes wear across the filesystem, even through reboots. The entropy actually comes from the filesystem itself, by xoring together all of the CRCs in the metadata-pairs on the filesystem. While this sounds like a ridiculous operation, it's easy to do when we already scan the metadata-pairs at mount time. This gives us a random number we can use for block allocation. Unfortunately it's not a great general purpose random generator as the output only changes every filesystem write. Fortunately that's exactly when we need our allocator. --- Additionally, the randomization created a mess for the testing framework. Fortunately, this method of randomization is deterministic. A very useful property for reproducing bugs.
Diffstat (limited to 'emubd')
-rw-r--r--emubd/lfs_emubd.c104
-rw-r--r--emubd/lfs_emubd.h4
2 files changed, 97 insertions, 11 deletions
diff --git a/emubd/lfs_emubd.c b/emubd/lfs_emubd.c
index 682ad92..de63057 100644
--- a/emubd/lfs_emubd.c
+++ b/emubd/lfs_emubd.c
@@ -19,6 +19,40 @@
#include <inttypes.h>
+// Emulated block device utils
+static inline void lfs_emubd_tole32(lfs_emubd_t *emu) {
+ emu->cfg.read_size = lfs_tole32(emu->cfg.read_size);
+ emu->cfg.prog_size = lfs_tole32(emu->cfg.prog_size);
+ emu->cfg.block_size = lfs_tole32(emu->cfg.block_size);
+ emu->cfg.block_count = lfs_tole32(emu->cfg.block_count);
+
+ emu->stats.read_count = lfs_tole32(emu->stats.read_count);
+ emu->stats.prog_count = lfs_tole32(emu->stats.prog_count);
+ emu->stats.erase_count = lfs_tole32(emu->stats.erase_count);
+
+ for (int i = 0; i < sizeof(emu->history.blocks) /
+ sizeof(emu->history.blocks[0]); i++) {
+ emu->history.blocks[i] = lfs_tole32(emu->history.blocks[i]);
+ }
+}
+
+static inline void lfs_emubd_fromle32(lfs_emubd_t *emu) {
+ emu->cfg.read_size = lfs_fromle32(emu->cfg.read_size);
+ emu->cfg.prog_size = lfs_fromle32(emu->cfg.prog_size);
+ emu->cfg.block_size = lfs_fromle32(emu->cfg.block_size);
+ emu->cfg.block_count = lfs_fromle32(emu->cfg.block_count);
+
+ emu->stats.read_count = lfs_fromle32(emu->stats.read_count);
+ emu->stats.prog_count = lfs_fromle32(emu->stats.prog_count);
+ emu->stats.erase_count = lfs_fromle32(emu->stats.erase_count);
+
+ for (int i = 0; i < sizeof(emu->history.blocks) /
+ sizeof(emu->history.blocks[0]); i++) {
+ emu->history.blocks[i] = lfs_fromle32(emu->history.blocks[i]);
+ }
+}
+
+
// Block device emulated on existing filesystem
int lfs_emubd_create(const struct lfs_config *cfg, const char *path) {
lfs_emubd_t *emu = cfg->context;
@@ -46,20 +80,39 @@ int lfs_emubd_create(const struct lfs_config *cfg, const char *path) {
}
// Load stats to continue incrementing
- snprintf(emu->child, LFS_NAME_MAX, "stats");
+ snprintf(emu->child, LFS_NAME_MAX, ".stats");
FILE *f = fopen(emu->path, "r");
if (!f) {
- return -errno;
- }
+ memset(&emu->stats, 0, sizeof(emu->stats));
+ } else {
+ size_t res = fread(&emu->stats, sizeof(emu->stats), 1, f);
+ lfs_emubd_fromle32(emu);
+ if (res < 1) {
+ return -errno;
+ }
- size_t res = fread(&emu->stats, sizeof(emu->stats), 1, f);
- if (res < 1) {
- return -errno;
+ err = fclose(f);
+ if (err) {
+ return -errno;
+ }
}
- err = fclose(f);
- if (err) {
- return -errno;
+ // Load history
+ snprintf(emu->child, LFS_NAME_MAX, ".history");
+ f = fopen(emu->path, "r");
+ if (!f) {
+ memset(&emu->history, 0, sizeof(emu->history));
+ } else {
+ size_t res = fread(&emu->history, sizeof(emu->history), 1, f);
+ lfs_emubd_fromle32(emu);
+ if (res < 1) {
+ return -errno;
+ }
+
+ err = fclose(f);
+ if (err) {
+ return -errno;
+ }
}
return 0;
@@ -161,6 +214,13 @@ int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
return -errno;
}
+ // update history and stats
+ if (block != emu->history.blocks[0]) {
+ memcpy(&emu->history.blocks[1], &emu->history.blocks[0],
+ sizeof(emu->history) - sizeof(emu->history.blocks[0]));
+ emu->history.blocks[0] = block;
+ }
+
emu->stats.prog_count += 1;
return 0;
}
@@ -206,13 +266,15 @@ int lfs_emubd_sync(const struct lfs_config *cfg) {
lfs_emubd_t *emu = cfg->context;
// Just write out info/stats for later lookup
- snprintf(emu->child, LFS_NAME_MAX, "config");
+ snprintf(emu->child, LFS_NAME_MAX, ".config");
FILE *f = fopen(emu->path, "w");
if (!f) {
return -errno;
}
+ lfs_emubd_tole32(emu);
size_t res = fwrite(&emu->cfg, sizeof(emu->cfg), 1, f);
+ lfs_emubd_fromle32(emu);
if (res < 1) {
return -errno;
}
@@ -222,13 +284,33 @@ int lfs_emubd_sync(const struct lfs_config *cfg) {
return -errno;
}
- snprintf(emu->child, LFS_NAME_MAX, "stats");
+ snprintf(emu->child, LFS_NAME_MAX, ".stats");
f = fopen(emu->path, "w");
if (!f) {
return -errno;
}
+ lfs_emubd_tole32(emu);
res = fwrite(&emu->stats, sizeof(emu->stats), 1, f);
+ lfs_emubd_fromle32(emu);
+ if (res < 1) {
+ return -errno;
+ }
+
+ err = fclose(f);
+ if (err) {
+ return -errno;
+ }
+
+ snprintf(emu->child, LFS_NAME_MAX, ".history");
+ f = fopen(emu->path, "w");
+ if (!f) {
+ return -errno;
+ }
+
+ lfs_emubd_tole32(emu);
+ res = fwrite(&emu->history, sizeof(emu->history), 1, f);
+ lfs_emubd_fromle32(emu);
if (res < 1) {
return -errno;
}
diff --git a/emubd/lfs_emubd.h b/emubd/lfs_emubd.h
index 0fd4387..64afa3e 100644
--- a/emubd/lfs_emubd.h
+++ b/emubd/lfs_emubd.h
@@ -46,6 +46,10 @@ typedef struct lfs_emubd {
} stats;
struct {
+ lfs_block_t blocks[4];
+ } history;
+
+ struct {
uint32_t read_size;
uint32_t prog_size;
uint32_t block_size;