diff --git a/components/fatfs/Kconfig b/components/fatfs/Kconfig index 3dda859da4..9cb067c7c6 100644 --- a/components/fatfs/Kconfig +++ b/components/fatfs/Kconfig @@ -182,14 +182,23 @@ menu "FAT Filesystem support" config FATFS_USE_FASTSEEK - bool "Enable fast seek algorithm when using f_lseek function" + bool "Enable fast seek algorithm when using lseek function through VFS FAT" default n help The fast seek feature enables fast backward/long seek operations without FAT access by using an in-memory CLMT (cluster link map table). It is applied to f_read and f_write function as well, however, - the file size cannot be expanded by f_write. - f_lseek function while the file is at fast seek mode. + the file size cannot be expanded by write function. + config FATFS_FAST_SEEK_BUFFER_SIZE + int "Fast seek CLMT buffer size" + default 64 + depends on FATFS_USE_FASTSEEK + help + If fast seek algorithm is enabled, this defines the size of + CLMT buffer used by this algorithm in 32-bit word units. + This value should be chosen based on prior knowledge of + maximum elements of each file entry would store. + endmenu diff --git a/components/fatfs/vfs/vfs_fat.c b/components/fatfs/vfs/vfs_fat.c index 102cb9602b..34de1bad94 100644 --- a/components/fatfs/vfs/vfs_fat.c +++ b/components/fatfs/vfs/vfs_fat.c @@ -307,6 +307,7 @@ static int vfs_fat_open(void* ctx, const char * path, int flags, int mode) errno = ENFILE; return -1; } + FRESULT res = f_open(&fat_ctx->files[fd], path, fat_mode_conv(flags)); if (res != FR_OK) { file_cleanup(fat_ctx, fd); @@ -315,6 +316,34 @@ static int vfs_fat_open(void* ctx, const char * path, int flags, int mode) errno = fresult_to_errno(res); return -1; } + +#ifdef CONFIG_FATFS_USE_FASTSEEK + FIL* file = &fat_ctx->files[fd]; + DWORD *clmt_mem = ff_memalloc(sizeof(DWORD) * CONFIG_FATFS_FAST_SEEK_BUFFER_SIZE); + if (clmt_mem == NULL) { + f_close(file); + file_cleanup(fat_ctx, fd); + _lock_release(&fat_ctx->lock); + ESP_LOGE(TAG, "open: Failed to pre-allocate CLMT buffer for fast-seek"); + errno = ENOMEM; + return -1; + } + + file->cltbl = clmt_mem; + file->cltbl[0] = CONFIG_FATFS_FAST_SEEK_BUFFER_SIZE; + res = f_lseek(file, CREATE_LINKMAP); + ESP_LOGD(TAG, "%s: fast-seek has: %s", + __func__, + (res == FR_OK) ? "activated" : "failed"); + if(res != FR_OK) { + ESP_LOGW(TAG, "%s: fast-seek not activated reason code: %d", + __func__, res); + //If linkmap creation fails, fallback to the non fast seek. + ff_memfree(file->cltbl); + file->cltbl = NULL; + } +#endif + // O_APPEND need to be stored because it is not compatible with FA_OPEN_APPEND: // - FA_OPEN_APPEND means to jump to the end of file only after open() // - O_APPEND means to jump to the end only before each write() @@ -465,6 +494,11 @@ static int vfs_fat_close(void* ctx, int fd) vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx; _lock_acquire(&fat_ctx->lock); FIL* file = &fat_ctx->files[fd]; + +#ifdef CONFIG_FATFS_USE_FASTSEEK + ff_memfree(file->cltbl); +#endif + FRESULT res = f_close(file); file_cleanup(fat_ctx, fd); _lock_release(&fat_ctx->lock); @@ -494,6 +528,9 @@ static off_t vfs_fat_lseek(void* ctx, int fd, off_t offset, int mode) errno = EINVAL; return -1; } + + ESP_LOGD(TAG, "%s: offset=%ld, filesize:=%d", __func__, new_pos, f_size(file)); + FRESULT res = f_lseek(file, new_pos); if (res != FR_OK) { ESP_LOGD(TAG, "%s: fresult=%d", __func__, res); diff --git a/tools/ci/config/target-test.yml b/tools/ci/config/target-test.yml index 613e178757..e0a9c30225 100644 --- a/tools/ci/config/target-test.yml +++ b/tools/ci/config/target-test.yml @@ -345,6 +345,7 @@ UT_002: UT_003: extends: .unit_test_template + parallel: 2 tags: - ESP32_IDF - UT_T1_SDMODE diff --git a/tools/unit-test-app/configs/fatfs_fast_seek b/tools/unit-test-app/configs/fatfs_fast_seek new file mode 100644 index 0000000000..b0c6966f2a --- /dev/null +++ b/tools/unit-test-app/configs/fatfs_fast_seek @@ -0,0 +1,3 @@ +TEST_COMPONENTS=fatfs +CONFIG_FATFS_USE_FASTSEEK=y +CONFIG_FATFS_FAST_SEEK_BUFFER_SIZE=64 \ No newline at end of file