mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
spiffs: add esp_spiffs_gc function to force garbage collection
Closes https://github.com/espressif/esp-idf/issues/8626
This commit is contained in:
parent
199d72c19c
commit
7c65370d84
@ -42,7 +42,7 @@ menu "SPIFFS Configuration"
|
||||
config SPIFFS_GC_MAX_RUNS
|
||||
int "Set Maximum GC Runs"
|
||||
default 10
|
||||
range 1 255
|
||||
range 1 10000
|
||||
help
|
||||
Define maximum number of GC runs to perform to reach desired free pages.
|
||||
|
||||
|
@ -378,6 +378,24 @@ esp_err_t esp_spiffs_format(const char* partition_label)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_spiffs_gc(const char* partition_label, size_t size_to_gc)
|
||||
{
|
||||
int index;
|
||||
if (esp_spiffs_by_label(partition_label, &index) != ESP_OK) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
int res = SPIFFS_gc(_efs[index]->fs, size_to_gc);
|
||||
if (res != SPIFFS_OK) {
|
||||
ESP_LOGE(TAG, "SPIFFS_gc failed, %d", res);
|
||||
SPIFFS_clearerr(_efs[index]->fs);
|
||||
if (res == SPIFFS_ERR_FULL) {
|
||||
return ESP_ERR_NOT_FINISHED;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_vfs_spiffs_register(const esp_vfs_spiffs_conf_t * conf)
|
||||
{
|
||||
assert(conf->base_path);
|
||||
|
@ -95,6 +95,35 @@ esp_err_t esp_spiffs_info(const char* partition_label, size_t *total_bytes, size
|
||||
*/
|
||||
esp_err_t esp_spiffs_check(const char* partition_label);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Perform garbage collection in SPIFFS partition
|
||||
*
|
||||
* Call this function to run GC and ensure that at least the given amount of
|
||||
* space is available in the partition. This function will fail with ESP_ERR_NOT_FINISHED
|
||||
* if it is not possible to reclaim the requested space (that is, not enough free
|
||||
* or deleted pages in the filesystem). This function will also fail if it fails to
|
||||
* reclaim the requested space after CONFIG_SPIFFS_GC_MAX_RUNS number of GC iterations.
|
||||
* On one GC iteration, SPIFFS will erase one logical block (4kB). Therefore the value
|
||||
* of CONFIG_SPIFFS_GC_MAX_RUNS should be set at least to the maximum expected size_to_gc,
|
||||
* divided by 4096. For example, if the application expects to make room for a 1MB file and
|
||||
* calls esp_spiffs_gc(label, 1024 * 1024), CONFIG_SPIFFS_GC_MAX_RUNS should be set to
|
||||
* at least 256.
|
||||
* On the other hand, increasing CONFIG_SPIFFS_GC_MAX_RUNS value increases the maximum
|
||||
* amount of time for which any SPIFFS GC or write operation may potentially block.
|
||||
*
|
||||
* @param partition_label Label of the partition to be garbage-collected.
|
||||
* The partition must be already mounted.
|
||||
* @param size_to_gc The number of bytes that the GC process should attempt
|
||||
* to make available.
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_NOT_FINISHED if GC fails to reclaim the size given by size_to_gc
|
||||
* - ESP_ERR_INVALID_STATE if the partition is not mounted
|
||||
* - ESP_FAIL on all other errors
|
||||
*/
|
||||
esp_err_t esp_spiffs_gc(const char* partition_label, size_t size_to_gc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_random.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
const char* spiffs_test_hello_str = "Hello, World!\n";
|
||||
@ -828,3 +829,85 @@ TEST_CASE("utime() works well", "[spiffs]")
|
||||
test_teardown();
|
||||
}
|
||||
#endif // CONFIG_SPIFFS_USE_MTIME
|
||||
|
||||
static void test_spiffs_rw_speed(const char* filename, void* buf, size_t buf_size, size_t file_size, bool is_write)
|
||||
{
|
||||
const size_t buf_count = file_size / buf_size;
|
||||
|
||||
FILE* f = fopen(filename, (is_write) ? "wb" : "rb");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
|
||||
struct timeval tv_start;
|
||||
gettimeofday(&tv_start, NULL);
|
||||
for (size_t n = 0; n < buf_count; ++n) {
|
||||
if (is_write) {
|
||||
TEST_ASSERT_EQUAL(buf_size, write(fileno(f), buf, buf_size));
|
||||
} else {
|
||||
if (read(fileno(f), buf, buf_size) != buf_size) {
|
||||
printf("reading at n=%d, eof=%d", n, feof(f));
|
||||
TEST_FAIL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct timeval tv_end;
|
||||
gettimeofday(&tv_end, NULL);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
|
||||
float t_s = tv_end.tv_sec - tv_start.tv_sec + 1e-6f * (tv_end.tv_usec - tv_start.tv_usec);
|
||||
printf("%s %d bytes (block size %d) in %.3fms (%.3f MB/s)\n",
|
||||
(is_write)?"Wrote":"Read", file_size, buf_size, t_s * 1e3,
|
||||
file_size / (1024.0f * 1024.0f * t_s));
|
||||
}
|
||||
|
||||
TEST_CASE("write/read speed test", "[spiffs][timeout=60]")
|
||||
{
|
||||
/* Erase partition before running the test to get consistent results */
|
||||
const esp_partition_t* part = get_test_data_partition();
|
||||
esp_partition_erase_range(part, 0, part->size);
|
||||
|
||||
test_setup();
|
||||
|
||||
const size_t buf_size = 16 * 1024;
|
||||
uint32_t* buf = (uint32_t*) calloc(1, buf_size);
|
||||
esp_fill_random(buf, buf_size);
|
||||
const size_t file_size = 256 * 1024;
|
||||
const char* file = "/spiffs/256k.bin";
|
||||
|
||||
test_spiffs_rw_speed(file, buf, 4 * 1024, file_size, true);
|
||||
TEST_ASSERT_EQUAL(0, unlink(file));
|
||||
TEST_ESP_OK(esp_spiffs_gc(spiffs_test_partition_label, file_size));
|
||||
|
||||
test_spiffs_rw_speed(file, buf, 8 * 1024, file_size, true);
|
||||
TEST_ASSERT_EQUAL(0, unlink(file));
|
||||
TEST_ESP_OK(esp_spiffs_gc(spiffs_test_partition_label, file_size));
|
||||
|
||||
test_spiffs_rw_speed(file, buf, 16 * 1024, file_size, true);
|
||||
|
||||
test_spiffs_rw_speed(file, buf, 4 * 1024, file_size, false);
|
||||
test_spiffs_rw_speed(file, buf, 8 * 1024, file_size, false);
|
||||
test_spiffs_rw_speed(file, buf, 16 * 1024, file_size, false);
|
||||
TEST_ASSERT_EQUAL(0, unlink(file));
|
||||
TEST_ESP_OK(esp_spiffs_gc(spiffs_test_partition_label, file_size));
|
||||
|
||||
free(buf);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("SPIFFS garbage-collect", "[spiffs][timeout=60]")
|
||||
{
|
||||
// should fail until the partition is initialized
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_spiffs_gc(spiffs_test_partition_label, 4096));
|
||||
|
||||
test_setup();
|
||||
|
||||
// reclaiming one block should be possible
|
||||
TEST_ESP_OK(esp_spiffs_gc(spiffs_test_partition_label, 4096));
|
||||
|
||||
// shouldn't be possible to reclaim more than the partition size
|
||||
const esp_partition_t* part = get_test_data_partition();
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FINISHED, esp_spiffs_gc(spiffs_test_partition_label, part->size * 2));
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
@ -26,3 +26,7 @@ CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y
|
||||
CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL=y
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3000
|
||||
CONFIG_MQTT_TEST_BROKER_URI="mqtt://${EXAMPLE_MQTT_BROKER_TCP}"
|
||||
# Set sufficient number of GC runs for SPIFFS:
|
||||
# size of the storage partition divided by flash sector size.
|
||||
# See esp_spiffs_gc description for more info.
|
||||
CONFIG_SPIFFS_GC_MAX_RUNS=132
|
||||
|
Loading…
x
Reference in New Issue
Block a user