Reorganized lfsr_mount/lfsr_format to better reuse code
Added lfsr_mountinited/lfsr_formatinited, mostly so lfsr_formatinited can just call lfsr_mountinited for its mount-check. This also leads to a nice consolidation of the cleanup-on-error part of lfsr_mount/lfsr_format.
This commit is contained in:
@@ -4377,12 +4377,142 @@ static lfs_ssize_t lfsr_superconfig_todisk(lfs_t *lfs,
|
|||||||
static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg);
|
static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg);
|
||||||
static int lfs_deinit(lfs_t *lfs);
|
static int lfs_deinit(lfs_t *lfs);
|
||||||
|
|
||||||
int lfsr_format(lfs_t *lfs, const struct lfs_config *cfg) {
|
static int lfsr_mountinited(lfs_t *lfs) {
|
||||||
|
// scan for the first non-fake superblock
|
||||||
|
lfsr_mpair_t mpair = LFSR_MPAIR(0, 1);
|
||||||
|
lfsr_mdir_t mdir;
|
||||||
|
while (true) {
|
||||||
|
// TODO detect cycles with Brent's algorithm
|
||||||
|
|
||||||
|
// fetch next possible superblock
|
||||||
|
int err = lfsr_mdir_fetch(lfs, &mdir, mpair, NULL);
|
||||||
|
if (err) {
|
||||||
|
LFS_ERROR("No littlefs superblock found");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// has magic string?
|
||||||
|
lfs_ssize_t id;
|
||||||
|
lfsr_tag_t tag;
|
||||||
|
lfsr_data_t data;
|
||||||
|
err = lfsr_mdir_lookupnext(lfs, &mdir, -1, LFSR_TAG_SUPERMAGIC,
|
||||||
|
&id, &tag, NULL, &data);
|
||||||
|
if (err && err != LFS_ERR_NOENT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err
|
||||||
|
|| id != -1
|
||||||
|
|| tag != LFSR_TAG_SUPERMAGIC
|
||||||
|
|| lfsr_data_size(data) != 8) {
|
||||||
|
LFS_ERROR("No littlefs magic found");
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmp;
|
||||||
|
err = lfsr_data_cmp(lfs, data, 0, "littlefs", 8, &cmp);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmp != 0) {
|
||||||
|
LFS_ERROR("No littlefs magic found");
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup the superconfig
|
||||||
|
err = lfsr_mdir_lookupnext(lfs, &mdir, -1, LFSR_TAG_SUPERCONFIG,
|
||||||
|
&id, &tag, NULL, &data);
|
||||||
|
if (err && err != LFS_ERR_NOENT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(err
|
||||||
|
|| id != -1
|
||||||
|
|| tag != LFSR_TAG_SUPERCONFIG)) {
|
||||||
|
// check the major/minor version
|
||||||
|
uint32_t major_version;
|
||||||
|
uint32_t minor_version;
|
||||||
|
|
||||||
|
lfs_size_t d = 0;
|
||||||
|
lfs_ssize_t d_ = lfsr_data_readleb128(lfs, data, d, &major_version);
|
||||||
|
if (d_ < 0) {
|
||||||
|
// treat leb128 overflow as an out-of-range value
|
||||||
|
if (d_ == LFS_ERR_CORRUPT) {
|
||||||
|
LFS_ERROR("Undecodable major version");
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
return d_;
|
||||||
|
}
|
||||||
|
d += d_;
|
||||||
|
|
||||||
|
d_ = lfsr_data_readleb128(lfs, data, d, &minor_version);
|
||||||
|
if (d_ < 0) {
|
||||||
|
// treat leb128 overflow as an out-of-range value
|
||||||
|
if (d_ == LFS_ERR_CORRUPT) {
|
||||||
|
LFS_ERROR("Undecodable minor version");
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
return d_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (major_version != LFS_DISK_VERSION_MAJOR
|
||||||
|
|| minor_version > LFS_DISK_VERSION_MINOR) {
|
||||||
|
LFS_ERROR("Incompatible version v%"PRIu32".%"PRIu32,
|
||||||
|
major_version, minor_version);
|
||||||
|
return LFS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO parse rest of the superblock
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup supermdir
|
||||||
|
//
|
||||||
|
// if we have a supermdir, this is actually a fake superblock and
|
||||||
|
// we need to parse the next superblock in the chain
|
||||||
|
err = lfsr_mdir_lookupnext(lfs, &mdir, -1, LFSR_TAG_SUPERMDIR,
|
||||||
|
&id, &tag, NULL, &data);
|
||||||
|
if (err && err != LFS_ERR_NOENT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no more supermdirs means we found our real superblock!
|
||||||
|
if (err
|
||||||
|
|| id != -1
|
||||||
|
|| tag != LFSR_TAG_SUPERMDIR) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs_ssize_t d = lfsr_mpair_fromdisk(lfs, &mpair, data);
|
||||||
|
if (d < 0) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lfsr_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||||
int err = lfs_init(lfs, cfg);
|
int err = lfs_init(lfs, cfg);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = lfsr_mountinited(lfs);
|
||||||
|
if (err) {
|
||||||
|
// make sure we clean up on error
|
||||||
|
lfs_deinit(lfs);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lfsr_unmount(lfs_t *lfs) {
|
||||||
|
return lfs_deinit(lfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lfsr_formatinited(lfs_t *lfs) {
|
||||||
uint8_t buf[LFSR_SUPERCONFIG_DSIZE];
|
uint8_t buf[LFSR_SUPERCONFIG_DSIZE];
|
||||||
lfs_ssize_t d = lfsr_superconfig_todisk(lfs,
|
lfs_ssize_t d = lfsr_superconfig_todisk(lfs,
|
||||||
&(lfsr_superconfig_t){
|
&(lfsr_superconfig_t){
|
||||||
@@ -4400,8 +4530,7 @@ int lfsr_format(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
},
|
},
|
||||||
buf);
|
buf);
|
||||||
if (d < 0) {
|
if (d < 0) {
|
||||||
err = d;
|
return d;
|
||||||
goto failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
@@ -4409,162 +4538,41 @@ int lfsr_format(lfs_t *lfs, const struct lfs_config *cfg) {
|
|||||||
// avoid mounting an older filesystem on disk
|
// avoid mounting an older filesystem on disk
|
||||||
lfsr_rbyd_t rbyd = {.block=i, .rev=1, .off=0, .trunk=0};
|
lfsr_rbyd_t rbyd = {.block=i, .rev=1, .off=0, .trunk=0};
|
||||||
|
|
||||||
err = lfsr_bd_erase(lfs, rbyd.block);
|
int err = lfsr_bd_erase(lfs, rbyd.block);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto failed;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = lfsr_rbyd_commit(lfs, &rbyd, LFSR_ATTRS(
|
err = lfsr_rbyd_commit(lfs, &rbyd, LFSR_ATTRS(
|
||||||
LFSR_ATTR(-1, SUPERMAGIC, 0, "littlefs", 8),
|
LFSR_ATTR(-1, SUPERMAGIC, 0, "littlefs", 8),
|
||||||
LFSR_ATTR(-1, SUPERCONFIG, 0, buf, d)));
|
LFSR_ATTR(-1, SUPERCONFIG, 0, buf, d)));
|
||||||
if (err) {
|
if (err) {
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to fetch the supermdir to check if format completed successfully
|
|
||||||
lfsr_mdir_t mdir;
|
|
||||||
err = lfsr_mdir_fetch(lfs, &mdir, LFSR_MPAIR(0, 1), NULL);
|
|
||||||
if (err) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lfs_deinit(lfs);
|
|
||||||
|
|
||||||
failed:
|
|
||||||
lfs_deinit(lfs);
|
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test that mount works with our formatted disk
|
||||||
|
int err = lfsr_mountinited(lfs);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lfsr_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
int lfsr_format(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||||
int err = lfs_init(lfs, cfg);
|
int err = lfs_init(lfs, cfg);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// scan for the first non-fake superblock
|
err = lfsr_formatinited(lfs);
|
||||||
lfsr_mpair_t mpair = LFSR_MPAIR(0, 1);
|
|
||||||
lfsr_mdir_t mdir;
|
|
||||||
while (true) {
|
|
||||||
// TODO detect cycles with Brent's algorithm
|
|
||||||
|
|
||||||
// fetch next possible superblock
|
|
||||||
int err = lfsr_mdir_fetch(lfs, &mdir, mpair, NULL);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ERROR("No littlefs superblock found");
|
// make sure we clean up on error
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// has magic string?
|
|
||||||
lfs_ssize_t id;
|
|
||||||
lfsr_tag_t tag;
|
|
||||||
lfsr_data_t data;
|
|
||||||
err = lfsr_mdir_lookupnext(lfs, &mdir, -1, LFSR_TAG_SUPERMAGIC,
|
|
||||||
&id, &tag, NULL, &data);
|
|
||||||
if (err && err != LFS_ERR_NOENT) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err
|
|
||||||
|| id != -1
|
|
||||||
|| tag != LFSR_TAG_SUPERMAGIC
|
|
||||||
|| lfsr_data_size(data) != 8) {
|
|
||||||
LFS_ERROR("No littlefs magic found");
|
|
||||||
err = LFS_ERR_INVAL;
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cmp;
|
|
||||||
err = lfsr_data_cmp(lfs, data, 0, "littlefs", 8, &cmp);
|
|
||||||
if (err) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmp != 0) {
|
|
||||||
LFS_ERROR("No littlefs magic found");
|
|
||||||
err = LFS_ERR_INVAL;
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// lookup the superconfig
|
|
||||||
err = lfsr_mdir_lookupnext(lfs, &mdir, -1, LFSR_TAG_SUPERCONFIG,
|
|
||||||
&id, &tag, NULL, &data);
|
|
||||||
if (err && err != LFS_ERR_NOENT) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(err
|
|
||||||
|| id != -1
|
|
||||||
|| tag != LFSR_TAG_SUPERCONFIG)) {
|
|
||||||
// check the major/minor version
|
|
||||||
uint32_t major_version;
|
|
||||||
uint32_t minor_version;
|
|
||||||
|
|
||||||
lfs_size_t d = 0;
|
|
||||||
lfs_ssize_t d_ = lfsr_data_readleb128(lfs, data, d, &major_version);
|
|
||||||
if (d_ < 0) {
|
|
||||||
// treat leb128 overflow as an out-of-range value
|
|
||||||
if (d_ == LFS_ERR_CORRUPT) {
|
|
||||||
LFS_ERROR("Undecodable major version");
|
|
||||||
err = LFS_ERR_INVAL;
|
|
||||||
}
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
d += d_;
|
|
||||||
|
|
||||||
d_ = lfsr_data_readleb128(lfs, data, d, &minor_version);
|
|
||||||
if (d_ < 0) {
|
|
||||||
// treat leb128 overflow as an out-of-range value
|
|
||||||
if (d_ == LFS_ERR_CORRUPT) {
|
|
||||||
LFS_ERROR("Undecodable minor version");
|
|
||||||
err = LFS_ERR_INVAL;
|
|
||||||
}
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (major_version != LFS_DISK_VERSION_MAJOR
|
|
||||||
|| minor_version > LFS_DISK_VERSION_MINOR) {
|
|
||||||
LFS_ERROR("Incompatible version v%"PRIu32".%"PRIu32,
|
|
||||||
major_version, minor_version);
|
|
||||||
err = LFS_ERR_INVAL;
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO parse rest of the superblock
|
|
||||||
}
|
|
||||||
|
|
||||||
// lookup supermdir
|
|
||||||
//
|
|
||||||
// if we have a supermdir, this is actually a fake superblock and
|
|
||||||
// we need to parse the next superblock in the chain
|
|
||||||
err = lfsr_mdir_lookupnext(lfs, &mdir, -1, LFSR_TAG_SUPERMDIR,
|
|
||||||
&id, &tag, NULL, &data);
|
|
||||||
if (err && err != LFS_ERR_NOENT) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no more supermdirs means we found our real superblock!
|
|
||||||
if (err
|
|
||||||
|| id != -1
|
|
||||||
|| tag != LFSR_TAG_SUPERMDIR) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lfs_ssize_t d = lfsr_mpair_fromdisk(lfs, &mpair, data);
|
|
||||||
if (d < 0) {
|
|
||||||
err = d;
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
failed:
|
|
||||||
lfs_deinit(lfs);
|
lfs_deinit(lfs);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lfsr_unmount(lfs_t *lfs) {
|
|
||||||
return lfs_deinit(lfs);
|
return lfs_deinit(lfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user