We create a FreeRTOS-FAT test to create/write files using FreeRTOS-FAT on SD card. The test is multi-threading. From test result, we get 4 files with same long file name (fstest_dump_task_0x3971_file_idx_0.bin), while the short file names are different.
The sdcard can mount and read/write in Linux and no error message pop-up
Would it be difficult for me to reproduce this? I guess that I need 4 tasks that run in parallel and created files with the same LFN?
As you know, the SFN is “composed” by the driver, using certain standard rules to translate an LFN to a SFN.
The result it not what you want, but looking at the code, it is as expected:
Task 1 creates “fstest_dump_task_0x3971_file_idx_0.bin”, which results in a SFN “FSTEST~1.BIN”.
Task 2 creates the same LFN, and the driver looks for the next available SFN, which is “FSTEST~2.BIN”.
But this is not what you want. Task 2 should not be able to succeed to create a file with mentioned LFN. It should get an error as long as task-1 has an open write handle to this file.
I will have a closer look.
I would be grateful if you can attach some testing code.
Task 1 creates “fstest_dump_task_0x3971_file_idx_0.bin”, which results in a SFN “FSTEST~1.BIN”.
Task 2 creates the same LFN, and the driver looks for the next available SFN, which is “FSTEST~2.BIN”.
But this is not what you want. Task 2 should not be able to succeed to create a file with mentioned LFN. It should get an error as long as task-1 has an open write handle to this file.
But this is not what you want. Task 2 should not be able to succeed to create a file with mentioned LFN. It should get an error as long as task-1 has an open write handle to this file.
For above test code, sometime there is “open fail” (see bellow log)
The the first file (idx_0) are all created for the four tasks
And then the following files (idx_1/2/…), the task may return “open fail”
FF_Open may need to be protected by FF_PendSemaphore( pxIOManager->pvSemaphore )
Test log (get “open fail” sometimes)
Conduct test for fs
task 0x3971 file 0 is written:fstest_dump_task_0x3971_file_idx_0.bin
task 0x3971 file 0 is written:fstest_dump_task_0x3971_file_idx_0.bin
task 0x3971 file 0 is written:fstest_dump_task_0x3971_file_idx_0.bin
task 0x3971 file 0 is written:fstest_dump_task_0x3971_file_idx_0.bin
Open file fail
task 0x3971 done: writtae sk1 0 f0xil39e7s1, jfoiline n1u imbse wrr=1it
en:fstest_dump_task_0x3971_file_idx_1.bin
task 0x3971 file 1 is written:fstest_dump_task_0x3971_file_idx_1.bin
task 0x3971 file 1 is written:fstest_dump_task_0x3971_file_idx_1.bin
Open file fail
eask 0x3971 done: writtaes k 100x 3f9il7e1s f,i ljoe i2n insu mbwreir=t2t
n:fstest_dump_task_0x3971_file_idx_2.bin
task 0x3971 file 2 is written:fstest_dump_task_0x3971_file_idx_2.bin
task 0x3971 file 3 is written:fstest_dump_task_0x3971_file_idx_3.bin
task 0x3971 file 3 is written:fstest_dump_task_0x3971_file_idx_3.bin
task 0x3971 file 4 is written:fstest_dump_task_0x3971_file_idx_4.bin
task 0x3971 file 4 is written:fstest_dump_task_0x3971_file_idx_4.bin
task 0x3971 file 5 is written:fstest_dump_task_0x3971_file_idx_5.bin
task 0x3971 file 5 is written:fstest_dump_task_0x3971_file_idx_5.bin
While I am unfamiliar with the FAT codebase, I see a potential race condition in your code: *task_ptr = *task_ptr + 1;. This line will be executed by all tasks in parallel and if they somehow coincide, it’ll lead to a different value.
I would suggest that you use task notifications in such scenarios. See this example: FreeRTOS task notifications.
Thank you for this well documented report. It also works for me, I can reproduce the problem.
It looks indeed like a race between equal-priority tasks, which are trying to create the same object. When ff_fopen() returns a creation error, that is actually good.
The code would only close the file in case of an error. And also I would swap the COUNT and SIZE parameters of fwrite(), so you can see how many bytes (not blocks) have actually been written:
FF_Open may need to be protected by FF_PendSemaphore( pxIOManager->pvSemaphore )
That will stop the race indeed!
The standard semaphore can not be used for this though: it would lead to a dead-lock.
There is also a lock of “directory access”, and a lock on the FAT, but those are not-recursive.
What I did is add a new semaphore called pvSemaphoreOpen:
And protect the function FF_Open() with it, but only if a file is to be created.
I tested it and it works perfectly: only a single instance of each LFN (long file name) will be created on disk. Other tasks all receive an error because task-1 still has an open handle.
I would like to make it conditional on some macro.