From 1d36fc606a8cf5a17d59227e6c2ccc25783fd839 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 5 Mar 2017 14:11:52 -0600 Subject: [PATCH] Added initial superblock definition Really started working out how the internal structure of the driver will be organized. There are a few hazy lines between the intended data structures with the goal of code reuse, so the function boundaries may end up a bit weird. --- lfs.c | 342 +++++++++++++++++++++++++++++++++++++++++++-------- lfs.h | 73 +++++++++-- lfs_config.h | 3 + 3 files changed, 360 insertions(+), 58 deletions(-) diff --git a/lfs.c b/lfs.c index 997a3be..950b2ab 100644 --- a/lfs.c +++ b/lfs.c @@ -29,6 +29,49 @@ static uint32_t lfs_crc(const uint8_t *data, lfs_size_t size, uint32_t crc) { static lfs_error_t lfs_alloc(lfs_t *lfs, lfs_ino_t *ino); static lfs_error_t lfs_free(lfs_t *lfs, lfs_ino_t ino); +// Disk structures +//lfs_disk_struct lfs_disk_free { +// lfs_ino_t head; +// uint32_t ioff; +// uint32_t icount; +// uint32_t rev; +//}; +// +//lfs_disk_struct lfs_disk_dir { +// uint32_t rev; +// uint32_t count; +// lfs_ino_t tail[2]; +// struct lfs_disk_free free; +//}; +// +//lfs_disk_struct lfs_disk_dirent { +// uint16_t type; +// uint16_t len; +//}; +// +//lfs_disk_struct lfs_disk_superblock { +// struct lfs_disk_dir dir; +// struct lfs_disk_dirent header; +// char magic[4]; +// uint32_t read_size; +// uint32_t write_size; +// uint32_t erase_size; +// uint32_t erase_count; +//}; +// +//lfs_disk_struct lfs_disk_dirent_file { +// struct lfs_disk_dirent header; +// lfs_ino_t head; +// lfs_size_t size; +// char name[LFS_NAME_MAX]; +//}; +// +//lfs_disk_struct lfs_disk_dirent_dir { +// struct lfs_disk_dirent header; +// lfs_ino_t ino[2]; +// char name[LFS_NAME_MAX]; +//}; + // Next index offset static lfs_off_t lfs_inext(lfs_t *lfs, lfs_off_t ioff) { @@ -114,21 +157,220 @@ static lfs_error_t lfs_iappend(lfs_t *lfs, lfs_ino_t *headp, // Memory managment static lfs_error_t lfs_alloc(lfs_t *lfs, lfs_ino_t *ino) { - lfs_error_t err = lfs_ifind(lfs, lfs->free.head, - lfs->free.icount, lfs->free.ioff, ino); + // TODO save slot for freeing? + lfs_error_t err = lfs_ifind(lfs, lfs->free.d.head, + lfs->free.d.icount, lfs->free.d.ioff, ino); if (err) { return err; } - lfs->free.ioff = lfs_inext(lfs, lfs->free.ioff); + lfs->free.d.ioff = lfs_inext(lfs, lfs->free.d.ioff); return lfs->ops->erase(lfs->bd, *ino, 0, lfs->info.erase_size); } static lfs_error_t lfs_free(lfs_t *lfs, lfs_ino_t ino) { - return lfs_iappend(lfs, &lfs->free.head, &lfs->free.icount, ino); + return lfs_iappend(lfs, &lfs->free.d.head, &lfs->free.d.icount, ino); } +// create a dir +// create entry +// update entry + + +//static lfs_error_t lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir); +//static lfs_error_t lfs_dir_update(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry); +//static lfs_error_t lfs_dir_destroy(lfs_t *lfs, lfs_dir_t *dir); +//static lfs_error_t lfs_entry_alloc(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry); +//static lfs_error_t lfs_entry_update(lfs_t *lfs, lfs_entry_t *entry); +//static lfs_error_t lfs_entry_destroy(lfs_t *lfs, lfs_dir_t *dir); + +// Directory operations +static lfs_error_t lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir) { + // Allocate pair of dir blocks + for (int i = 0; i < 2; i++) { + int err = lfs_alloc(lfs, &dir->dno[i]); + if (err) { + return err; + } + } + + // Rather than clobbering one of the blocks we just pretend + // the revision may be valid + int err = lfs->ops->read(lfs->bd, (void*)&dir->d.rev, dir->dno[1], 0, 4); + if (err) { + return err; + } + dir->d.rev += 1; + + // Other defaults + dir->d.size = sizeof(struct lfs_disk_dir); + dir->d.tail[0] = 0; + dir->d.tail[1] = 0; + dir->d.parent[0] = 0; + dir->d.parent[1] = 0; + return 0; +} + +lfs_error_t lfs_dir_update(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { + // TODO flush this + dir->d.free = lfs->free.d; + + // Start by erasing target block + int err = lfs->ops->erase(lfs->bd, dir->dno[0], 0, lfs->info.erase_size); + + // Write header and start calculating crc + uint32_t crc = lfs_crc((void*)&dir->d, sizeof(dir->d), 0xffffffff); + err = lfs->ops->write(lfs->bd, (void*)&dir->d, + dir->dno[0], 0, sizeof(dir->d)); + if (err) { + return err; + } + + // Copy over entries and write optional entry update + // TODO handle optional entry + for (lfs_off_t i = sizeof(dir->d); i < lfs->info.erase_size-4; i += 4) { + uint32_t data; + err = lfs->ops->read(lfs->bd, (void*)&data, dir->dno[1], i, 4); + if (err) { + return err; + } + + crc = lfs_crc((void*)&data, 4, crc); + err = lfs->ops->write(lfs->bd, (void*)&data, dir->dno[0], i, 4); + if (err) { + return err; + } + } + + // Write resulting crc + err = lfs->ops->write(lfs->bd, (void*)&crc, + dir->dno[0], lfs->info.erase_size-4, 4); + if (err) { + return err; + } + + // Flip dnos to indicate next write of the dir pair + lfs_ino_t temp = dir->dno[0]; + dir->dno[0] = dir->dno[1]; + dir->dno[1] = temp; + + return 0; +} + + +//static lfs_error_t lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir) { +// memset(dir, 0, sizeof(lfs_dir_t)); +// +// for (int i = 0; i < 2; i++) { +// int err = lfs_alloc(lfs, &dir->dno[i]); +// if (err) { +// return err; +// } +// } +// +// // Rather than clobbering one of the blocks we just pretend +// // the revision may be valid +// int err = lfs->ops->read(lfs->bd, (void*)&dir->rev, dir->dno[1], 0, 4); +// if (err) { +// return err; +// } +// dir->rev += 1; +// +// // TODO move this to a flush of some sort? +// struct lfs_disk_dir disk_dir = { +// .rev = dir->rev, +// .count = dir->len, +// .tail[0] = dir->tail[0], +// .tail[1] = dir->tail[1], +// .free.head = lfs->free.head, +// .free.ioff = lfs->free.ioff, +// .free.icount = lfs->free.icount, +// .free.rev = lfs->free.rev, +// }; +// +// err = lfs->ops->write(lfs->bd, (void*)&disk_dir, +// dir->dno[0], 0, sizeof(struct lfs_disk_dir)); +// if (err) { +// return err; +// } +// +// uint32_t crc = 0xffffffff; +// for (lfs_off_t i = 0; i < lfs->info.erase_size-4; i += 4) { +// uint32_t data; +// err = lfs->ops->read(lfs->bd, (void*)&data, dir->dno[0], i, 4); +// if (err) { +// return err; +// } +// +// crc = lfs_crc((void*)&data, 4, crc); +// } +// +// err = lfs->ops->write(lfs->bd, (void*)&crc, +// dir->dno[0], lfs->info.erase_size-4, 4); +// if (err) { +// return err; +// } +// +// lfs_ino_t temp = dir->dno[0]; +// dir->dno[0] = dir->dno[1]; +// dir->dno[1] = temp; +// +// return 0; +//} + +//lfs_error_t lfs_dir_update(lfs_t *lfs, lfs_dir_t *dir, +// lfs_dirent_t *ent, const char *name) { +// +// +// +// struct lfs_disk_dir disk_dir = { +// .rev = dir->rev, +// .count = dir->len, +// .tail[0] = dir->tail[0], +// .tail[1] = dir->tail[1], +// // TODO flush this? +// .free.head = lfs->free.head, +// .free.ioff = lfs->free.ioff, +// .free.icount = lfs->free.icount, +// .free.rev = lfs->free.rev, +// }; +// +// err = lfs->ops->write(lfs->bd, (void*)&disk_dir, +// dir->dno[0], 0, sizeof(struct lfs_disk_dir)); +// if (err) { +// return err; +// } +// +// if (ent) { +// // TODO update entry +// } +// +// uint32_t crc = 0xffffffff; +// for (lfs_off_t i = 0; i < lfs->info.erase_size-4; i += 4) { +// uint32_t data; +// err = lfs->ops->read(lfs->bd, (void*)&data, dir->dno[0], i, 4); +// if (err) { +// return err; +// } +// +// crc = lfs_crc((void*)&data, 4, crc); +// } +// +// err = lfs->ops->write(lfs->bd, (void*)&crc, +// dir->dno[0], lfs->info.erase_size-4, 4); +// if (err) { +// return err; +// } +// +// lfs_ino_t temp = dir->dno[0]; +// dir->dno[0] = dir->dno[1]; +// dir->dno[1] = temp; +// +// return 0; +//} + + // Little filesystem operations lfs_error_t lfs_create(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *ops) { lfs->bd = bd; @@ -157,10 +399,10 @@ lfs_error_t lfs_format(lfs_t *lfs) { // TODO make sure that erase clobbered blocks { // Create free list - lfs->free.head = 4; - lfs->free.ioff = 1; - lfs->free.icount = 1; - lfs->free.rev = 1; + lfs->free.d.head = 4; + lfs->free.d.ioff = 1; + lfs->free.d.icount = 1; + lfs->free.d.rev = 1; lfs_size_t block_count = lfs->info.total_size / lfs->info.erase_size; for (lfs_ino_t i = 5; i < block_count; i++) { @@ -171,68 +413,66 @@ lfs_error_t lfs_format(lfs_t *lfs) { } } + lfs_dir_t root; { // Write root directory - struct __attribute__((packed)) { - lfs_word_t rev; - lfs_size_t len; - lfs_ino_t tail[2]; - struct lfs_free_list free; - } header = {1, 0, {0, 0}, lfs->free}; - err = lfs->ops->write(lfs->bd, (void*)&header, 2, 0, sizeof(header)); + int err = lfs_dir_alloc(lfs, &root); if (err) { return err; } - uint32_t crc = lfs_crc((void*)&header, sizeof(header), 0xffffffff); - - for (lfs_size_t i = sizeof(header); i < info.erase_size-4; i += 4) { - uint32_t data; - err = lfs->ops->read(lfs->bd, (void*)&data, 2, i, 4); - if (err) { - return err; - } - - crc = lfs_crc((void*)&data, 4, crc); - } - - err = lfs->ops->write(lfs->bd, (void*)&crc, 2, info.erase_size-4, 4); + err = lfs_dir_update(lfs, &root, 0); if (err) { return err; } } { - // Write superblock - struct __attribute__((packed)) { - lfs_word_t rev; - lfs_word_t len; - lfs_word_t tail[2]; - struct lfs_free_list free; - char magic[4]; - struct lfs_bd_info info; - } header = {1, 0, {2, 3}, {0}, {"lfs"}, info}; - err = lfs->ops->write(lfs->bd, (void*)&header, 0, 0, sizeof(header)); - if (err) { - return err; - } + // Write superblocks + lfs_ino_t sno[2] = {0, 1}; + lfs_superblock_t superblock = { + .d.rev = 1, + .d.count = 0, + .d.root = {root.dno[0], root.dno[1]}, + .d.magic = {"littlefs"}, + .d.block_size = info.erase_size, + .d.block_count = info.total_size / info.erase_size, + }; - uint32_t crc = lfs_crc((void*)&header, sizeof(header), 0xffffffff); - - for (lfs_size_t i = sizeof(header); i < info.erase_size-4; i += 4) { - uint32_t data; - err = lfs->ops->read(lfs->bd, (void*)&data, 0, i, 4); + for (int i = 0; i < 2; i++) { + err = lfs->ops->erase(lfs->bd, sno[i], 0, info.erase_size); if (err) { return err; } - crc = lfs_crc((void*)&data, 4, crc); + err = lfs->ops->write(lfs->bd, (void*)&superblock.d, + sno[i], 0, sizeof(superblock.d)); + if (err) { + return err; + } + + uint32_t crc = lfs_crc((void*)&superblock.d, + sizeof(superblock.d), 0xffffffff); + + for (lfs_size_t i = sizeof(superblock); + i < info.erase_size-4; i += 4) { + uint32_t data; + err = lfs->ops->read(lfs->bd, (void*)&data, 0, i, 4); + if (err) { + return err; + } + + crc = lfs_crc((void*)&data, 4, crc); + } + + err = lfs->ops->write(lfs->bd, (void*)&crc, + sno[i], info.erase_size-4, 4); + if (err) { + return err; + } } - err = lfs->ops->write(lfs->bd, (void*)&crc, 0, info.erase_size-4, 4); - if (err) { - return err; - } + // TODO verify superblocks written correctly } diff --git a/lfs.h b/lfs.h index d3c1207..fd431a1 100644 --- a/lfs.h +++ b/lfs.h @@ -10,22 +10,81 @@ #include "lfs_config.h" #include "lfs_bd.h" -struct lfs_free_list { - lfs_ino_t head; - lfs_word_t ioff; - lfs_word_t icount; - lfs_word_t rev; -}; +// Data structures +typedef struct lfs_free { + lfs_disk_struct lfs_disk_free { + lfs_ino_t head; + lfs_word_t ioff; + lfs_word_t icount; + lfs_word_t rev; + } d; +} lfs_free_t; + +typedef struct lfs_dir { + lfs_ino_t dno[2]; + + lfs_disk_struct lfs_disk_dir { + lfs_word_t rev; + lfs_size_t size; + lfs_ino_t tail[2]; + lfs_ino_t parent[2]; + + struct lfs_disk_free free; + } d; +} lfs_dir_t; + +typedef struct lfs_entry { + lfs_ino_t dir[2]; + lfs_off_t off; + + lfs_disk_struct lfs_disk_entry { + uint16_t type; + uint16_t len; + union { + lfs_disk_struct { + lfs_ino_t head; + lfs_size_t size; + char name[LFS_NAME_MAX]; + } file; + lfs_disk_struct { + lfs_ino_t dir[2]; + char name[LFS_NAME_MAX]; + } dir; + lfs_disk_struct { + char magic[4]; + uint32_t read_size; + uint32_t write_size; + uint32_t erase_size; + uint32_t erase_count; + } superblock; + } value; + } d; +} lfs_entry_t; + +typedef struct lfs_superblock { + lfs_disk_struct lfs_disk_superblock { + uint32_t rev; + uint32_t count; + lfs_ino_t root[2]; + char magic[8]; + uint32_t block_size; + uint32_t block_count; + } d; +} lfs_superblock_t; + +// Little filesystem type typedef struct lfs { lfs_bd_t *bd; const struct lfs_bd_ops *ops; - struct lfs_free_list free; + lfs_free_t free; struct lfs_bd_info info; } lfs_t; +// Functions lfs_error_t lfs_create(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *bd_ops); lfs_error_t lfs_format(lfs_t *lfs); +lfs_error_t lfs_mount(lfs_t *lfs); #endif diff --git a/lfs_config.h b/lfs_config.h index e0191f3..717949b 100644 --- a/lfs_config.h +++ b/lfs_config.h @@ -42,4 +42,7 @@ static inline lfs_word_t lfs_npw2(lfs_word_t a) { return 32 - __builtin_clz(a-1); } +// Attributes +#define lfs_disk_struct struct __attribute__((packed)) + #endif