From f753434640c51e079f650e558beb3f761df29078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Tue, 27 Feb 2024 12:38:10 +0100 Subject: [PATCH 1/2] fix(storage/esp_partition): add option to control erase check during write for linux target --- components/esp_partition/Kconfig | 9 +++++++++ components/esp_partition/partition_linux.c | 2 ++ 2 files changed, 11 insertions(+) diff --git a/components/esp_partition/Kconfig b/components/esp_partition/Kconfig index 6a0159bc2a..9fa838f5bc 100644 --- a/components/esp_partition/Kconfig +++ b/components/esp_partition/Kconfig @@ -7,4 +7,13 @@ menu "Partition API Configuration" help This option enables gathering host test statistics and SPI flash wear levelling simulation. + config ESP_PARTITION_ERASE_CHECK + bool "Check if flash is erased before writing" + depends on IDF_TARGET_LINUX + default y + help + This option controls whether the partition implementation checks + if the flash is erased before writing to it. + This is necessary for SPIFFS, which expects to be able to write without erasing first. + endmenu diff --git a/components/esp_partition/partition_linux.c b/components/esp_partition/partition_linux.c index 0a1379ef21..3cf497d367 100644 --- a/components/esp_partition/partition_linux.c +++ b/components/esp_partition/partition_linux.c @@ -396,12 +396,14 @@ esp_err_t esp_partition_write(const esp_partition_t *partition, size_t dst_offse for (size_t x = 0; x < new_size; x++) { +#ifdef CONFIG_ESP_PARTITION_ERASE_CHECK // Check if address to be written was erased first if((~((uint8_t *)dst_addr)[x] & ((uint8_t *)src)[x]) != 0) { ESP_LOGW(TAG, "invalid flash operation detected"); ret = ESP_ERR_FLASH_OP_FAIL; break; } +#endif // CONFIG_ESP_PARTITION_ERASE_CHECK // AND with destination byte (to emulate real NOR FLASH behavior) ((uint8_t *)dst_addr)[x] &= ((uint8_t *)src)[x]; From c44da2f22240f0bd01a422a0a7dc82a7d2e58fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Mon, 27 May 2024 15:48:00 +0200 Subject: [PATCH 2/2] feat(storage/spiffs): add host test for disabled erase check --- .../spiffs/host_test/main/host_test_spiffs.c | 41 ++++++++++++++++++- .../spiffs/host_test/pytest_spiffs_linux.py | 1 + .../spiffs/host_test/sdkconfig.ci.erase_check | 1 + .../host_test/sdkconfig.ci.no_erase_check | 1 + 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 components/spiffs/host_test/sdkconfig.ci.erase_check create mode 100644 components/spiffs/host_test/sdkconfig.ci.no_erase_check diff --git a/components/spiffs/host_test/main/host_test_spiffs.c b/components/spiffs/host_test/main/host_test_spiffs.c index a16a0256a6..4fcfce13c1 100644 --- a/components/spiffs/host_test/main/host_test_spiffs.c +++ b/components/spiffs/host_test/main/host_test_spiffs.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -274,10 +274,49 @@ TEST(spiffs, can_read_spiffs_image) deinit_spiffs(&fs); } +TEST(spiffs, erase_check) +{ + spiffs fs; + + init_spiffs(&fs, 5); + + + for (int boot_iter = 0; boot_iter <= 10000; ++boot_iter) { + for (int write_iter = 0; write_iter < 1000; ++write_iter) { + spiffs_file f = SPIFFS_open(&fs, "/test", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0); + if (f < 0) { + fprintf(stderr, "Failed to open file\n"); +#if !CONFIG_ESP_PARTITION_ERASE_CHECK + TEST_FAIL(); +#endif + return; + } + const int data_sz = 7 * 1024; + char data[data_sz]; + memset(data, 0x55, data_sz); + int cb = SPIFFS_write(&fs, f, data, data_sz); + if (cb != data_sz) { + fprintf(stderr, "Failed to write file\n"); + TEST_FAIL(); + } + int rc = SPIFFS_close(&fs, f); + if (rc < 0) { + fprintf(stderr, "Failed to close file\n"); + TEST_FAIL(); + } + } + } + +#if CONFIG_ESP_PARTITION_ERASE_CHECK + TEST_FAIL(); +#endif +} + TEST_GROUP_RUNNER(spiffs) { RUN_TEST_CASE(spiffs, format_disk_open_file_write_and_read_file); RUN_TEST_CASE(spiffs, can_read_spiffs_image); + RUN_TEST_CASE(spiffs, erase_check); } static void run_all_tests(void) diff --git a/components/spiffs/host_test/pytest_spiffs_linux.py b/components/spiffs/host_test/pytest_spiffs_linux.py index b4719cc5f1..18dbd3f2cd 100644 --- a/components/spiffs/host_test/pytest_spiffs_linux.py +++ b/components/spiffs/host_test/pytest_spiffs_linux.py @@ -6,5 +6,6 @@ from pytest_embedded import Dut @pytest.mark.linux @pytest.mark.host_test +@pytest.mark.parametrize('config', ['erase_check', 'no_erase_check']) def test_spiffs_linux(dut: Dut) -> None: dut.expect_unity_test_output(timeout=5) diff --git a/components/spiffs/host_test/sdkconfig.ci.erase_check b/components/spiffs/host_test/sdkconfig.ci.erase_check new file mode 100644 index 0000000000..b82bb58187 --- /dev/null +++ b/components/spiffs/host_test/sdkconfig.ci.erase_check @@ -0,0 +1 @@ +CONFIG_ESP_PARTITION_ERASE_CHECK=y diff --git a/components/spiffs/host_test/sdkconfig.ci.no_erase_check b/components/spiffs/host_test/sdkconfig.ci.no_erase_check new file mode 100644 index 0000000000..51131d0744 --- /dev/null +++ b/components/spiffs/host_test/sdkconfig.ci.no_erase_check @@ -0,0 +1 @@ +CONFIG_ESP_PARTITION_ERASE_CHECK=n