summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Leech <andrew.leech@planetinnovation.com.au>2024-01-24 09:08:29 +1100
committerDamien George <damien@micropython.org>2025-04-03 15:08:58 +1100
commitb33b9f81217bb1521138a8064d1d1bee3eb49e0f (patch)
tree888d13e0a67d6ce6ee0f0e07803df306d53a7965
parentf96417dbf28617c533e4f2e65c65d1ed11f089fa (diff)
stm32/main: Catch and report corrupted lfs filesystem at startup.
On stm32, the startup code attempts to mount the configured filesystem. If there is an existing littlefs filesystem that's suitable corrupted it's possible for the reported blocksize to be incorrect here: uint32_t block_size = lfs2_fromle32(superblock->block_size); This `block_size` (which is read from the filesystem iteself) is used to create the len argument passed to `pyb_flash_make_new()`. In that function the len arg is validated to be a mutliple of the underlying hardware block size, as well as not bigger than the physical flash. Any failure is raised as a ValueError. This exception is not caught currently in main, it flows up to the high level assert / startup failure. As this occurs before `boot.py` is run, the users (potentially frozen) application code doesn't have any opportunity to detect and handle the issue. This commit adds a helper function which attempts to create a block device, and on error returns `None` instead of raising an exception. Using this in main means that a potentially corrupt filesystem will simply remain unmounted, and the application can handle the issue safely. The fix here also handles the case where the littlefs filesystem is valid but the autodetection code (which detects the filesystem size) does not work correctly. In that case it will retry mounting the filesystem using the whole size of the block device. Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
-rw-r--r--ports/stm32/main.c11
-rw-r--r--ports/stm32/storage.c48
-rw-r--r--ports/stm32/storage.h4
3 files changed, 41 insertions, 22 deletions
diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index 55dbeed98..0f904a8ba 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -185,8 +185,15 @@ MP_NOINLINE static bool init_flash_fs(uint reset_mode) {
if (len != -1) {
// Detected a littlefs filesystem so create correct block device for it
- mp_obj_t args[] = { MP_OBJ_NEW_QSTR(MP_QSTR_len), MP_OBJ_NEW_SMALL_INT(len) };
- bdev = MP_OBJ_TYPE_GET_SLOT(&pyb_flash_type, make_new)(&pyb_flash_type, 0, 1, args);
+ mp_obj_t lfs_bdev = pyb_flash_new_obj(0, len);
+ if (lfs_bdev == mp_const_none) {
+ // Invalid len detected, filesystem header block likely corrupted.
+ // Create bdev with default size to attempt to mount the whole flash or
+ // let user attempt recovery if desired.
+ bdev = pyb_flash_new_obj(0, -1);
+ } else {
+ bdev = lfs_bdev;
+ }
}
#endif
diff --git a/ports/stm32/storage.c b/ports/stm32/storage.c
index a6594fd4d..d810261fb 100644
--- a/ports/stm32/storage.c
+++ b/ports/stm32/storage.c
@@ -273,6 +273,29 @@ const pyb_flash_obj_t pyb_flash_obj = {
0, // actual size handled in ioctl, MP_BLOCKDEV_IOCTL_BLOCK_COUNT case
};
+mp_obj_t pyb_flash_new_obj(mp_int_t start, mp_int_t len) {
+ uint32_t bl_len = (storage_get_block_count() - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE;
+
+ if (start == -1) {
+ start = 0;
+ } else if (!(0 <= start && start < bl_len && start % MICROPY_HW_BDEV_BLOCKSIZE_EXT == 0)) {
+ return mp_const_none;
+ }
+
+ if (len == -1) {
+ len = bl_len - start;
+ } else if (!(0 < len && start + len <= bl_len && len % MICROPY_HW_BDEV_BLOCKSIZE_EXT == 0)) {
+ return mp_const_none;
+ }
+
+ pyb_flash_obj_t *self = mp_obj_malloc(pyb_flash_obj_t, &pyb_flash_type);
+ self->use_native_block_size = false;
+ self->start = start;
+ self->len = len;
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
static void pyb_flash_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_flash_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (self == &pyb_flash_obj) {
@@ -296,30 +319,15 @@ static mp_obj_t pyb_flash_make_new(const mp_obj_type_t *type, size_t n_args, siz
// Default singleton object that accesses entire flash, including virtual partition table
return MP_OBJ_FROM_PTR(&pyb_flash_obj);
}
-
- pyb_flash_obj_t *self = mp_obj_malloc(pyb_flash_obj_t, &pyb_flash_type);
- self->use_native_block_size = false;
-
- uint32_t bl_len = (storage_get_block_count() - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE;
-
mp_int_t start = args[ARG_start].u_int;
- if (start == -1) {
- start = 0;
- } else if (!(0 <= start && start < bl_len && start % MICROPY_HW_BDEV_BLOCKSIZE_EXT == 0)) {
- mp_raise_ValueError(NULL);
- }
-
mp_int_t len = args[ARG_len].u_int;
- if (len == -1) {
- len = bl_len - start;
- } else if (!(0 < len && start + len <= bl_len && len % MICROPY_HW_BDEV_BLOCKSIZE_EXT == 0)) {
+
+ mp_obj_t self = pyb_flash_new_obj(start, len);
+ if (self == mp_const_none) {
+ // Invalid start or end arg
mp_raise_ValueError(NULL);
}
-
- self->start = start;
- self->len = len;
-
- return MP_OBJ_FROM_PTR(self);
+ return self;
}
static mp_obj_t pyb_flash_readblocks(size_t n_args, const mp_obj_t *args) {
diff --git a/ports/stm32/storage.h b/ports/stm32/storage.h
index 05654855a..accf6c390 100644
--- a/ports/stm32/storage.h
+++ b/ports/stm32/storage.h
@@ -77,4 +77,8 @@ extern const struct _pyb_flash_obj_t pyb_flash_obj;
struct _fs_user_mount_t;
void pyb_flash_init_vfs(struct _fs_user_mount_t *vfs);
+#if !BUILDING_MBOOT
+mp_obj_t pyb_flash_new_obj(mp_int_t start, mp_int_t len);
+#endif
+
#endif // MICROPY_INCLUDED_STM32_STORAGE_H