Merge branch 'bugfix/spiffs_obj_name_len_check' into 'master'

SPIFFS: fix issues with formatting and page size limit

See merge request idf/esp-idf!1866
This commit is contained in:
Ivan Grokhotkov
2018-02-01 12:18:39 +08:00
4 changed files with 111 additions and 48 deletions

View File

@@ -5,16 +5,14 @@ config SPIFFS_MAX_PARTITIONS
default 3 default 3
range 1 10 range 1 10
help help
Define maximum number of partitions Define maximum number of partitions that can be mounted.
that can be mounted.
menu "SPIFFS Cache Configuration" menu "SPIFFS Cache Configuration"
config SPIFFS_CACHE config SPIFFS_CACHE
bool "Enable SPIFFS Cache" bool "Enable SPIFFS Cache"
default "y" default "y"
help help
Enables/disable memory read Enables/disable memory read caching of nucleus file system
caching of nucleus file system
operations. operations.
config SPIFFS_CACHE_WR config SPIFFS_CACHE_WR
@@ -22,16 +20,14 @@ config SPIFFS_CACHE_WR
default "y" default "y"
depends on SPIFFS_CACHE depends on SPIFFS_CACHE
help help
Enables memory write caching for Enables memory write caching for file descriptors in hydrogen.
file descriptors in hydrogen.
config SPIFFS_CACHE_STATS config SPIFFS_CACHE_STATS
bool "Enable SPIFFS Cache Statistics" bool "Enable SPIFFS Cache Statistics"
default "n" default "n"
depends on SPIFFS_CACHE depends on SPIFFS_CACHE
help help
Enable/disable statistics on caching. Enable/disable statistics on caching. Debug/test purpose only.
Debug/test purpose only.
endmenu endmenu
@@ -39,44 +35,54 @@ config SPIFFS_PAGE_CHECK
bool "Enable SPIFFS Page Check" bool "Enable SPIFFS Page Check"
default "y" default "y"
help help
Always check header of each Always check header of each accessed page to ensure consistent state.
accessed page to ensure consistent state. If enabled it will increase number of reads from flash, especially
If enabled it will increase number if cache is disabled.
of reads, will increase flash.
config SPIFFS_GC_MAX_RUNS config SPIFFS_GC_MAX_RUNS
int "Set Maximum GC Runs" int "Set Maximum GC Runs"
default 10 default 10
range 1 255 range 1 255
help help
Define maximum number of gc runs to Define maximum number of GC runs to perform to reach desired free pages.
perform to reach desired free pages.
config SPIFFS_GC_STATS config SPIFFS_GC_STATS
bool "Enable SPIFFS GC Statistics" bool "Enable SPIFFS GC Statistics"
default "n" default "n"
help help
Enable/disable statistics on gc. Enable/disable statistics on gc. Debug/test purpose only.
Debug/test purpose only.
config SPIFFS_PAGE_SIZE
int "SPIFFS logical page size"
default 256
range 256 1024
help
Logical page size of SPIFFS partition, in bytes. Must be multiple
of flash page size (which is usually 256 bytes).
Larger page sizes reduce overhead when storing large files, and
improve filesystem performance when reading large files.
Smaller page sizes reduce overhead when storing small (< page size)
files.
config SPIFFS_OBJ_NAME_LEN config SPIFFS_OBJ_NAME_LEN
int "Set SPIFFS Maximum Name Length" int "Set SPIFFS Maximum Name Length"
default 32 default 32
range 1 256 range 1 256
help help
Object name maximum length. Note that this length Object name maximum length. Note that this length include the
include the zero-termination character, zero-termination character, meaning maximum string of characters
meaning maximum string of characters can at most be can at most be SPIFFS_OBJ_NAME_LEN - 1.
SPIFFS_OBJ_NAME_LEN - 1.
SPIFFS_OBJ_NAME_LEN + SPIFFS_META_LENGTH should not exceed
SPIFFS_PAGE_SIZE - 64.
config SPIFFS_USE_MAGIC config SPIFFS_USE_MAGIC
bool "Enable SPIFFS Filesystem Magic" bool "Enable SPIFFS Filesystem Magic"
default "y" default "y"
help help
Enable this to have an identifiable spiffs filesystem. Enable this to have an identifiable spiffs filesystem.
This will look for a magic in all sectors This will look for a magic in all sectors to determine if this
to determine if this is a valid spiffs system is a valid spiffs system or not at mount time.
or not on mount point.
config SPIFFS_USE_MAGIC_LENGTH config SPIFFS_USE_MAGIC_LENGTH
bool "Enable SPIFFS Filesystem Length Magic" bool "Enable SPIFFS Filesystem Length Magic"
@@ -96,6 +102,9 @@ config SPIFFS_META_LENGTH
These bytes can be used in an application-specific manner. These bytes can be used in an application-specific manner.
Set this to at least 4 bytes to enable support for saving file Set this to at least 4 bytes to enable support for saving file
modification time. modification time.
SPIFFS_OBJ_NAME_LEN + SPIFFS_META_LENGTH should not exceed
SPIFFS_PAGE_SIZE - 64.
config SPIFFS_USE_MTIME config SPIFFS_USE_MTIME
bool "Save file modification time" bool "Save file modification time"
@@ -113,45 +122,39 @@ config SPIFFS_DBG
bool "Enable general SPIFFS debug" bool "Enable general SPIFFS debug"
default "n" default "n"
help help
Enabling this option will print Enabling this option will print general debug mesages to the console.
general debug mesages to the console
config SPIFFS_API_DBG config SPIFFS_API_DBG
bool "Enable SPIFFS API debug" bool "Enable SPIFFS API debug"
default "n" default "n"
help help
Enabling this option will print Enabling this option will print API debug mesages to the console.
API debug mesages to the console
config SPIFFS_GC_DBG config SPIFFS_GC_DBG
bool "Enable SPIFFS Garbage Cleaner debug" bool "Enable SPIFFS Garbage Cleaner debug"
default "n" default "n"
help help
Enabling this option will print Enabling this option will print GC debug mesages to the console.
GC debug mesages to the console
config SPIFFS_CACHE_DBG config SPIFFS_CACHE_DBG
bool "Enable SPIFFS Cache debug" bool "Enable SPIFFS Cache debug"
default "n" default "n"
depends on SPIFFS_CACHE depends on SPIFFS_CACHE
help help
Enabling this option will print Enabling this option will print cache debug mesages to the console.
Cache debug mesages to the console
config SPIFFS_CHECK_DBG config SPIFFS_CHECK_DBG
bool "Enable SPIFFS Filesystem Check debug" bool "Enable SPIFFS Filesystem Check debug"
default "n" default "n"
help help
Enabling this option will print Enabling this option will print Filesystem Check debug mesages
Filesystem Check debug mesages to the console.
to the console
config SPIFFS_TEST_VISUALISATION config SPIFFS_TEST_VISUALISATION
bool "Enable SPIFFS Filesystem Visualization" bool "Enable SPIFFS Filesystem Visualization"
default "n" default "n"
help help
Enable this option to enable SPIFFS_vis function Enable this option to enable SPIFFS_vis function in the API.
in the api.
endmenu endmenu

View File

@@ -222,6 +222,14 @@ static esp_err_t esp_spiffs_init(const esp_vfs_spiffs_conf_t* conf)
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
uint32_t flash_page_size = g_rom_flashchip.page_size;
uint32_t log_page_size = CONFIG_SPIFFS_PAGE_SIZE;
if (log_page_size % flash_page_size != 0) {
ESP_LOGE(TAG, "SPIFFS_PAGE_SIZE is not multiple of flash chip page size (%d)",
flash_page_size);
return ESP_ERR_INVALID_ARG;
}
esp_partition_subtype_t subtype = conf->partition_label ? esp_partition_subtype_t subtype = conf->partition_label ?
ESP_PARTITION_SUBTYPE_ANY : ESP_PARTITION_SUBTYPE_DATA_SPIFFS; ESP_PARTITION_SUBTYPE_ANY : ESP_PARTITION_SUBTYPE_DATA_SPIFFS;
const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
@@ -247,7 +255,7 @@ static esp_err_t esp_spiffs_init(const esp_vfs_spiffs_conf_t* conf)
efs->cfg.hal_read_f = spiffs_api_read; efs->cfg.hal_read_f = spiffs_api_read;
efs->cfg.hal_write_f = spiffs_api_write; efs->cfg.hal_write_f = spiffs_api_write;
efs->cfg.log_block_size = g_rom_flashchip.sector_size; efs->cfg.log_block_size = g_rom_flashchip.sector_size;
efs->cfg.log_page_size = g_rom_flashchip.page_size; efs->cfg.log_page_size = log_page_size;
efs->cfg.phys_addr = 0; efs->cfg.phys_addr = 0;
efs->cfg.phys_erase_block = g_rom_flashchip.sector_size; efs->cfg.phys_erase_block = g_rom_flashchip.sector_size;
efs->cfg.phys_size = partition->size; efs->cfg.phys_size = partition->size;
@@ -349,8 +357,12 @@ esp_err_t esp_spiffs_info(const char* partition_label, size_t *total_bytes, size
esp_err_t esp_spiffs_format(const char* partition_label) esp_err_t esp_spiffs_format(const char* partition_label)
{ {
bool mount_on_success = false; bool partition_was_mounted = false;
int index; int index;
/* If the partition is not mounted, need to create SPIFFS structures
* and mount the partition, unmount, format, delete SPIFFS structures.
* See SPIFFS wiki for the reason why.
*/
esp_err_t err = esp_spiffs_by_label(partition_label, &index); esp_err_t err = esp_spiffs_by_label(partition_label, &index);
if (err != ESP_OK) { if (err != ESP_OK) {
esp_vfs_spiffs_conf_t conf = { esp_vfs_spiffs_conf_t conf = {
@@ -363,23 +375,28 @@ esp_err_t esp_spiffs_format(const char* partition_label)
return err; return err;
} }
err = esp_spiffs_by_label(partition_label, &index); err = esp_spiffs_by_label(partition_label, &index);
if (err != ESP_OK) { assert(err == ESP_OK && "failed to get index of the partition just mounted");
return err;
}
esp_spiffs_free(&_efs[index]);
return ESP_OK;
} else if (SPIFFS_mounted(_efs[index]->fs)) { } else if (SPIFFS_mounted(_efs[index]->fs)) {
SPIFFS_unmount(_efs[index]->fs); partition_was_mounted = true;
mount_on_success = true;
} }
SPIFFS_unmount(_efs[index]->fs);
s32_t res = SPIFFS_format(_efs[index]->fs); s32_t res = SPIFFS_format(_efs[index]->fs);
if (res != SPIFFS_OK) { if (res != SPIFFS_OK) {
ESP_LOGE(TAG, "format failed, %i", SPIFFS_errno(_efs[index]->fs)); ESP_LOGE(TAG, "format failed, %i", SPIFFS_errno(_efs[index]->fs));
SPIFFS_clearerr(_efs[index]->fs); SPIFFS_clearerr(_efs[index]->fs);
/* If the partition was previously mounted, but format failed, don't
* try to mount the partition back (it will probably fail). On the
* other hand, if it was not mounted, need to clean up.
*/
if (!partition_was_mounted) {
esp_spiffs_free(&_efs[index]);
}
return ESP_FAIL; return ESP_FAIL;
} }
if (mount_on_success) { if (partition_was_mounted) {
res = SPIFFS_mount(_efs[index]->fs, &_efs[index]->cfg, _efs[index]->work, res = SPIFFS_mount(_efs[index]->fs, &_efs[index]->cfg, _efs[index]->work,
_efs[index]->fds, _efs[index]->fds_sz, _efs[index]->cache, _efs[index]->fds, _efs[index]->fds_sz, _efs[index]->cache,
_efs[index]->cache_sz, spiffs_api_check); _efs[index]->cache_sz, spiffs_api_check);
@@ -388,6 +405,8 @@ esp_err_t esp_spiffs_format(const char* partition_label)
SPIFFS_clearerr(_efs[index]->fs); SPIFFS_clearerr(_efs[index]->fs);
return ESP_FAIL; return ESP_FAIL;
} }
} else {
esp_spiffs_free(&_efs[index]);
} }
return ESP_OK; return ESP_OK;
} }

View File

@@ -153,12 +153,15 @@ extern void spiffs_api_unlock(struct spiffs_t *fs);
// changes the on-disk format, so the change is not backward-compatible. // changes the on-disk format, so the change is not backward-compatible.
// //
// Do note: the meta length must never exceed // Do note: the meta length must never exceed
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + 64) // logical_page_size - (SPIFFS_OBJ_NAME_LEN + SPIFFS_PAGE_EXTRA_SIZE)
// //
// This is derived from following: // This is derived from following:
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) + // logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) +
// spiffs_object_ix_header fields + at least some LUT entries) // spiffs_object_ix_header fields + at least some LUT entries)
#define SPIFFS_OBJ_META_LEN (CONFIG_SPIFFS_META_LENGTH) #define SPIFFS_OBJ_META_LEN (CONFIG_SPIFFS_META_LENGTH)
#define SPIFFS_PAGE_EXTRA_SIZE (64)
_Static_assert(SPIFFS_OBJ_META_LEN + SPIFFS_OBJ_NAME_LEN + SPIFFS_PAGE_EXTRA_SIZE
<= CONFIG_SPIFFS_PAGE_SIZE, "SPIFFS_OBJ_META_LEN or SPIFFS_OBJ_NAME_LEN too long");
// Size of buffer allocated on stack used when copying data. // Size of buffer allocated on stack used when copying data.
// Lower value generates more read/writes. No meaning having it bigger // Lower value generates more read/writes. No meaning having it bigger

View File

@@ -407,7 +407,7 @@ static void test_teardown()
TEST_ESP_OK(esp_vfs_spiffs_unregister(spiffs_test_partition_label)); TEST_ESP_OK(esp_vfs_spiffs_unregister(spiffs_test_partition_label));
} }
TEST_CASE("can format partition", "[spiffs]") TEST_CASE("can initialize SPIFFS in erased partition", "[spiffs]")
{ {
const esp_partition_t* part = get_test_data_partition(); const esp_partition_t* part = get_test_data_partition();
TEST_ASSERT_NOT_NULL(part); TEST_ASSERT_NOT_NULL(part);
@@ -420,6 +420,44 @@ TEST_CASE("can format partition", "[spiffs]")
test_teardown(); test_teardown();
} }
TEST_CASE("can format mounted partition", "[spiffs]")
{
// Mount SPIFFS, create file, format, check that the file does not exist.
const esp_partition_t* part = get_test_data_partition();
TEST_ASSERT_NOT_NULL(part);
test_setup();
const char* filename = "/spiffs/hello.txt";
test_spiffs_create_file_with_text(filename, spiffs_test_hello_str);
esp_spiffs_format(part->label);
FILE* f = fopen(filename, "r");
TEST_ASSERT_NULL(f);
test_teardown();
}
TEST_CASE("can format unmounted partition", "[spiffs]")
{
// Mount SPIFFS, create file, unmount. Format. Mount again, check that
// the file does not exist.
const esp_partition_t* part = get_test_data_partition();
TEST_ASSERT_NOT_NULL(part);
test_setup();
const char* filename = "/spiffs/hello.txt";
test_spiffs_create_file_with_text(filename, spiffs_test_hello_str);
test_teardown();
esp_spiffs_format(part->label);
// Don't use test_setup here, need to mount without formatting
esp_vfs_spiffs_conf_t conf = {
.base_path = "/spiffs",
.partition_label = spiffs_test_partition_label,
.max_files = 5,
.format_if_mount_failed = false
};
TEST_ESP_OK(esp_vfs_spiffs_register(&conf));
FILE* f = fopen(filename, "r");
TEST_ASSERT_NULL(f);
test_teardown();
}
TEST_CASE("can create and write file", "[spiffs]") TEST_CASE("can create and write file", "[spiffs]")
{ {
test_setup(); test_setup();