[Bug] dfs_elm.c 中因 open/close 逻辑不一致导致的内存泄漏
RT-Thread Version
Master
Hardware Type/Architectures
STM32F407
Develop Toolchain
RT-Thread Studio
Describe the bug
dfs/filesystems/elmfat/dfs_elm.c文件中的dfs_elm_open和dfs_elm_close函数在处理文件引用计数 (ref_count) 时的行为不一致,导致了严重的内存泄漏。
问题根源分析:
dfs_elm_open的行为: 无论一个文件被打开多少次 (ref_count值是多少),dfs_elm_open函数总是会为每一次open调用执行rt_malloc来分配一个新的底层文件句柄 (FIL或DIR结构体)。dfs_elm_close的行为: 与open的行为相反,dfs_elm_close函数在开始处包含一个检查if (file->vnode->ref_count > 1)。如果这个条件成立(意味着还有其他文件描述符指向同一个文件),函数会直接返回,并不会调用rt_free来释放当初为这个文件描述符在open时所分配的内存。
导致的后果:
这种 open (总是分配) 和 close (有条件释放) 之间的逻辑不对称,导致对同一个文件进行多次打开后,除了最后一次关闭操作外,之前所有的关闭操作都会跳过资源释放步骤,造成与关闭次数成正比的内存泄漏。
Steps to reproduce the behavior (复现步骤)
- 分析代码发现,尚未测试
- 该部分逻辑与littlefs类似,littlefs处理不会导致malloc与free不一致问题,但是会导致第二次open失败
Expected behavior (预期行为)
每一次 close(fd) 调用都应该精确地释放与之对应的 open() 操作所分配的内存资源 (FIL 或 DIR 结构体)。在上述测试代码的循环中,initial_mem 和 final_mem 的值应该保持一致(不考虑系统其他任务的微小波动),不应出现累积性的内存增长。
Add screenshot / media if you have them (截图)
(无)
Other additional context
这个问题的根源在于 dfs_elm.c 文件中 dfs_elm_close 函数的以下代码块:
int dfs_elm_close(struct dfs_file *file)
{
FRESULT result;
RT_ASSERT(file->vnode->ref_count > 0);
if (file->vnode->ref_count > 1)
{
return 0; // <--- 此处直接返回,导致内存泄漏
}
// ... 后续的释放逻辑 ...
}
建议的修复方案是直接移除这个 if (file->vnode->ref_count > 1) 判断,以确保 open 和 close 的资源管理行为是对称的。
另外,还有一个相关的逻辑不一致点:在 dfs_elm_open 函数中,对 ref_count 的检查仅在 FF_VOLUMES > 1 的宏条件下存在,而在单卷配置下则没有。虽然这不是导致内存泄漏的直接原因,但建议一并修复,以保证代码在不同配置下行为的统一性。
我明天看下
- 文件大小
msh /flash/log>ls
Directory /flash/log:
flash_sys.log 8093
- 未
cat文件内存占用
memory heap address:
name : heap
total : 95400
used : 50184
max_used: 52424
heap_ptr: 0x20008b38
lfree : 0x200097e8
heap_end: 0x2001fff0
- 第一次
cat文件内存占用
msh /flash/log>memtrace
memory heap address:
name : heap
total : 95400
used : 54344
max_used: 54872
heap_ptr: 0x20008b38
lfree : 0x200097e8
heap_end: 0x2001fff0
- 第10次
cat文件内存占用
msh /flash/log>memtrace
memory heap address:
name : heap
total : 95400
used : 87624
max_used: 88152
heap_ptr: 0x20008b38
lfree : 0x200097e8
heap_end: 0x2001fff0
- 解除文件打开状态,内存还是异常占用
Directory /flash/log:
flash_sys.log 8093
msh /flash/log>list fd
fd type ref magic path
-- ------ --- ----- ------
msh /flash/log>memc
memcheck
msh /flash/log>memt
memtrace
msh /flash/log>memtrace
memory heap address:
name : heap
total : 95400
used : 87056
max_used: 89248
heap_ptr: 0x20008b38
lfree : 0x200097e8
heap_end: 0x2001fff0
使用qemu-a9的BSP测试了下,发现貌似没这个问题?
测试代码:
#include <fcntl.h>
#include <unistd.h>
#define LEAK_TEST_FILE "/elm_leak_test.txt"
#define LEAK_TEST_PASSES 50
static void dump_heap_usage(const char *tag, rt_uint32_t *used_out)
{
rt_uint32_t total = 0;
rt_uint32_t used = 0;
rt_uint32_t max_used = 0;
rt_memory_info(&total, &used, &max_used);
if (used_out)
{
*used_out = used;
}
rt_kprintf("[%s] heap total=%u used=%u max=%u\n", tag, total, used, max_used);
}
int main(void)
{
rt_thread_mdelay(1000); /* wait for elm FAT filesystem to be mounted */
rt_kprintf("elm leak regression test start\n");
int init_fd = open(LEAK_TEST_FILE, O_CREAT | O_RDWR | O_TRUNC, 0);
if (init_fd < 0)
{
rt_kprintf("failed to create %s, err=%d\n", LEAK_TEST_FILE, init_fd);
return -1;
}
const char *payload = "elm leak repro";
(void)write(init_fd, payload, rt_strlen(payload));
close(init_fd);
rt_uint32_t used_before = 0;
dump_heap_usage("before", &used_before);
for (int i = 0; i < LEAK_TEST_PASSES; ++i)
{
int fd_a = open(LEAK_TEST_FILE, O_RDONLY);
if (fd_a < 0)
{
rt_kprintf("iteration %d: open A failed, err=%d\n", i, fd_a);
break;
}
int fd_b = open(LEAK_TEST_FILE, O_RDONLY);
if (fd_b < 0)
{
rt_kprintf("iteration %d: open B failed, err=%d\n", i, fd_b);
close(fd_a);
break;
}
close(fd_b);
close(fd_a);
if ((i + 1) % 10 == 0)
{
dump_heap_usage("progress", RT_NULL);
}
}
rt_uint32_t used_after = 0;
dump_heap_usage("after", &used_after);
rt_kprintf("heap leak delta=%d bytes after %d open/close pairs\n",
(int)(used_after - used_before), LEAK_TEST_PASSES);
return 0;
}
另外测试了下littlefs,发现会有这样的问题:
open同一个文件多次后,在close的第二次会出现断言,问题截图:
static void lfs_multi_open_repro_case(void)
{
int fd_primary = -1;
int fd_secondary = -1;
fd_primary = open(TEST_FILE_PATH, O_RDWR | O_CREAT | O_TRUNC, 0);
if (fd_primary < 0)
{
rt_kprintf("Failed to prepare littlefs test file '%s' (%d)\n", TEST_FILE_PATH, fd_primary);
return;
}
static const char payload[] = "RT-Thread littlefs multi-open reproduce\r\n";
int written = write(fd_primary, payload, sizeof(payload) - 1);
if (written < 0)
{
rt_kprintf("Failed to seed payload for littlefs test (%d)\n", written);
close(fd_primary);
unlink(TEST_FILE_PATH);
return;
}
close(fd_primary);
fd_primary = open(TEST_FILE_PATH, O_RDONLY, 0);
if (fd_primary < 0)
{
rt_kprintf("Failed to open baseline descriptor (%d)\n", fd_primary);
unlink(TEST_FILE_PATH);
return;
}
fd_secondary = open(TEST_FILE_PATH, O_RDONLY, 0);
if (fd_secondary < 0)
{
rt_kprintf("Second open failed unexpectedly (%d)\n", fd_secondary);
close(fd_primary);
unlink(TEST_FILE_PATH);
return;
}
rt_kprintf("littlefs multi-open reproduction ready: fd0=%d, fd1=%d\n", fd_primary, fd_secondary);
rt_kprintf("Closing fd0\n");
close(fd_primary);
rt_kprintf("Closing fd1\n");
close(fd_secondary);
unlink(TEST_FILE_PATH);
}
另外测试了下littlefs,发现会有这样的问题:
open同一个文件多次后,在close的第二次会出现断言,问题截图:
static void lfs_multi_open_repro_case(void) { int fd_primary = -1; int fd_secondary = -1;
fd_primary = open(TEST_FILE_PATH, O_RDWR | O_CREAT | O_TRUNC, 0); if (fd_primary < 0) { rt_kprintf("Failed to prepare littlefs test file '%s' (%d)\n", TEST_FILE_PATH, fd_primary); return; }
static const char payload[] = "RT-Thread littlefs multi-open reproduce\r\n"; int written = write(fd_primary, payload, sizeof(payload) - 1); if (written < 0) { rt_kprintf("Failed to seed payload for littlefs test (%d)\n", written); close(fd_primary); unlink(TEST_FILE_PATH); return; }
close(fd_primary);
fd_primary = open(TEST_FILE_PATH, O_RDONLY, 0); if (fd_primary < 0) { rt_kprintf("Failed to open baseline descriptor (%d)\n", fd_primary); unlink(TEST_FILE_PATH); return; }
fd_secondary = open(TEST_FILE_PATH, O_RDONLY, 0); if (fd_secondary < 0) { rt_kprintf("Second open failed unexpectedly (%d)\n", fd_secondary); close(fd_primary); unlink(TEST_FILE_PATH); return; }
rt_kprintf("littlefs multi-open reproduction ready: fd0=%d, fd1=%d\n", fd_primary, fd_secondary); rt_kprintf("Closing fd0\n"); close(fd_primary);
rt_kprintf("Closing fd1\n"); close(fd_secondary);
unlink(TEST_FILE_PATH); }
这个修复了吧
- https://github.com/RT-Thread-packages/littlefs/pull/28
使用qemu-a9的BSP测试了下,发现貌似没这个问题?
测试代码:
#include <fcntl.h> #include <unistd.h>
#define LEAK_TEST_FILE "/elm_leak_test.txt" #define LEAK_TEST_PASSES 50
static void dump_heap_usage(const char *tag, rt_uint32_t *used_out) { rt_uint32_t total = 0; rt_uint32_t used = 0; rt_uint32_t max_used = 0;
rt_memory_info(&total, &used, &max_used); if (used_out) { *used_out = used; } rt_kprintf("[%s] heap total=%u used=%u max=%u\n", tag, total, used, max_used);}
int main(void) { rt_thread_mdelay(1000); /* wait for elm FAT filesystem to be mounted */
rt_kprintf("elm leak regression test start\n"); int init_fd = open(LEAK_TEST_FILE, O_CREAT | O_RDWR | O_TRUNC, 0); if (init_fd < 0) { rt_kprintf("failed to create %s, err=%d\n", LEAK_TEST_FILE, init_fd); return -1; } const char *payload = "elm leak repro"; (void)write(init_fd, payload, rt_strlen(payload)); close(init_fd); rt_uint32_t used_before = 0; dump_heap_usage("before", &used_before); for (int i = 0; i < LEAK_TEST_PASSES; ++i) { int fd_a = open(LEAK_TEST_FILE, O_RDONLY); if (fd_a < 0) { rt_kprintf("iteration %d: open A failed, err=%d\n", i, fd_a); break; } int fd_b = open(LEAK_TEST_FILE, O_RDONLY); if (fd_b < 0) { rt_kprintf("iteration %d: open B failed, err=%d\n", i, fd_b); close(fd_a); break; } close(fd_b); close(fd_a); if ((i + 1) % 10 == 0) { dump_heap_usage("progress", RT_NULL); } } rt_uint32_t used_after = 0; dump_heap_usage("after", &used_after); rt_kprintf("heap leak delta=%d bytes after %d open/close pairs\n", (int)(used_after - used_before), LEAK_TEST_PASSES); return 0;}
- 文件打开关闭用的是open与close的话,根据这个问题来看或许是触发不了问题的.https://github.com/RT-Thread/rt-thread/issues/10848
- 使用dfs_file_open/dfs_file_close试一下应该可以复现?
- 或许先使用finsh的cat多次文件看看👀>?
void cat(const char *filename)
{
struct dfs_file fd;
int length = 0;
char buffer[81];
fd_init(&fd);
if (dfs_file_open(&fd, filename, O_RDONLY) < 0)
{
rt_kprintf("Open %s failed\n", filename);
return;
}
do
{
rt_memset(buffer, 0x0, sizeof(buffer));
length = dfs_file_read(&fd, (void *)buffer, sizeof(buffer) - 1);
if (length > 0)
{
buffer[length] = '\0';
rt_device_t out_device = rt_console_get_device();
rt_device_write(out_device, 0, (void *)buffer, length);
}
} while (length > 0);
rt_kprintf("\n");
dfs_file_close(&fd);
}
FINSH_FUNCTION_EXPORT(cat, print file);
另外测试了下littlefs,发现会有这样的问题: open同一个文件多次后,在close的第二次会出现断言,问题截图:
static void lfs_multi_open_repro_case(void) { int fd_primary = -1; int fd_secondary = -1; fd_primary = open(TEST_FILE_PATH, O_RDWR | O_CREAT | O_TRUNC, 0); if (fd_primary < 0) { rt_kprintf("Failed to prepare littlefs test file '%s' (%d)\n", TEST_FILE_PATH, fd_primary); return; } static const char payload[] = "RT-Thread littlefs multi-open reproduce\r\n"; int written = write(fd_primary, payload, sizeof(payload) - 1); if (written < 0) { rt_kprintf("Failed to seed payload for littlefs test (%d)\n", written); close(fd_primary); unlink(TEST_FILE_PATH); return; } close(fd_primary); fd_primary = open(TEST_FILE_PATH, O_RDONLY, 0); if (fd_primary < 0) { rt_kprintf("Failed to open baseline descriptor (%d)\n", fd_primary); unlink(TEST_FILE_PATH); return; } fd_secondary = open(TEST_FILE_PATH, O_RDONLY, 0); if (fd_secondary < 0) { rt_kprintf("Second open failed unexpectedly (%d)\n", fd_secondary); close(fd_primary); unlink(TEST_FILE_PATH); return; } rt_kprintf("littlefs multi-open reproduction ready: fd0=%d, fd1=%d\n", fd_primary, fd_secondary); rt_kprintf("Closing fd0\n"); close(fd_primary); rt_kprintf("Closing fd1\n"); close(fd_secondary); unlink(TEST_FILE_PATH); }
这个修复了吧
我测测哈,可能是我本地的太老了
另外测试了下littlefs,发现会有这样的问题: open同一个文件多次后,在close的第二次会出现断言,问题截图:
static void lfs_multi_open_repro_case(void) { int fd_primary = -1; int fd_secondary = -1; fd_primary = open(TEST_FILE_PATH, O_RDWR | O_CREAT | O_TRUNC, 0); if (fd_primary < 0) { rt_kprintf("Failed to prepare littlefs test file '%s' (%d)\n", TEST_FILE_PATH, fd_primary); return; } static const char payload[] = "RT-Thread littlefs multi-open reproduce\r\n"; int written = write(fd_primary, payload, sizeof(payload) - 1); if (written < 0) { rt_kprintf("Failed to seed payload for littlefs test (%d)\n", written); close(fd_primary); unlink(TEST_FILE_PATH); return; } close(fd_primary); fd_primary = open(TEST_FILE_PATH, O_RDONLY, 0); if (fd_primary < 0) { rt_kprintf("Failed to open baseline descriptor (%d)\n", fd_primary); unlink(TEST_FILE_PATH); return; } fd_secondary = open(TEST_FILE_PATH, O_RDONLY, 0); if (fd_secondary < 0) { rt_kprintf("Second open failed unexpectedly (%d)\n", fd_secondary); close(fd_primary); unlink(TEST_FILE_PATH); return; } rt_kprintf("littlefs multi-open reproduction ready: fd0=%d, fd1=%d\n", fd_primary, fd_secondary); rt_kprintf("Closing fd0\n"); close(fd_primary); rt_kprintf("Closing fd1\n"); close(fd_secondary); unlink(TEST_FILE_PATH); }
这个修复了吧
我测测哈,可能是我本地的太老了
可以的,修复了,我看看上面的问题
@wdfk-prog 测试了下,还是没能复现
master分支,qemu-a9:
5.1.0分支:
@wdfk-prog 测试了下,还是没能复现
master分支,qemu-a9:
5.1.0分支:
![]()
- 有一个地方open该文件还为close的情况下,进行cat该文件吗?
- 可以在
if (file->vnode->ref_count > 1)里面加个打印看看是否直接退出了?
int dfs_elm_close(struct dfs_file *file)
{
FRESULT result;
RT_ASSERT(file->vnode->ref_count > 0);
if (file->vnode->ref_count > 1)
{
return 0; // <--- 此处直接返回,导致内存泄漏
}
// ... 后续的释放逻辑 ...
}
- 我看你打印的日子ret cnt:1 不知道是啥时候的情况
@wdfk-prog 测试了下,还是没能复现 master分支,qemu-a9:
5.1.0分支:
- 有一个地方open该文件还为close的情况下,进行cat该文件吗?
- 可以在
if (file->vnode->ref_count > 1)里面加个打印看看是否直接退出了?int dfs_elm_close(struct dfs_file *file) { FRESULT result;
RT_ASSERT(file->vnode->ref_count > 0); if (file->vnode->ref_count > 1) { return 0; // <--- 此处直接返回,导致内存泄漏 } // ... 后续的释放逻辑 ...}
- 我看你打印的日子ret cnt:1 不知道是啥时候的情况
我就是在 if (file->vnode->ref_count > 1) 这边加的打印,发现都是1,可以给个稳定复现的测试代码不?
@wdfk-prog 测试了下,还是没能复现 master分支,qemu-a9:
5.1.0分支:
- 有一个地方open该文件还为close的情况下,进行cat该文件吗?
- 可以在
if (file->vnode->ref_count > 1)里面加个打印看看是否直接退出了?int dfs_elm_close(struct dfs_file *file) { FRESULT result;
RT_ASSERT(file->vnode->ref_count > 0); if (file->vnode->ref_count > 1) { return 0; // <--- 此处直接返回,导致内存泄漏 } // ... 后续的释放逻辑 ...}
- 我看你打印的日子ret cnt:1 不知道是啥时候的情况
我就是在
if (file->vnode->ref_count > 1)这边加的打印,发现都是1,可以给个稳定复现的测试代码不?
-
我知道了 https://github.com/RT-Thread/rt-thread/blob/6695599afcd365b0fe18e023c830b8260663f3cb/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c#L338-L365
-
应该是FF_VOLUMES配置的问题
-
你那边走到了 (FF_VOLUMES > 1)里面所以没问题
-
我这里走的是另一个逻辑 https://github.com/RT-Thread/rt-thread/blob/6695599afcd365b0fe18e023c830b8260663f3cb/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c#L366-L368
-
这一块宏里面的逻辑判断或许应该统一一下,哈哈哈
@wdfk-prog 测试了下,还是没能复现 master分支,qemu-a9:
5.1.0分支:
- 有一个地方open该文件还为close的情况下,进行cat该文件吗?
- 可以在
if (file->vnode->ref_count > 1)里面加个打印看看是否直接退出了?int dfs_elm_close(struct dfs_file *file) { FRESULT result;
RT_ASSERT(file->vnode->ref_count > 0); if (file->vnode->ref_count > 1) { return 0; // <--- 此处直接返回,导致内存泄漏 } // ... 后续的释放逻辑 ...}
- 我看你打印的日子ret cnt:1 不知道是啥时候的情况
我就是在
if (file->vnode->ref_count > 1)这边加的打印,发现都是1,可以给个稳定复现的测试代码不?
我知道了
[rt-thread/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c](https://github.com/RT-Thread/rt-thread/blob/6695599afcd365b0fe18e023c830b8260663f3cb/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c#L338-L365) Lines 338 to 365 in [6695599](/RT-Thread/rt-thread/commit/6695599afcd365b0fe18e023c830b8260663f3cb) #if (FF_VOLUMES > 1) int vol; struct dfs_filesystem *fs = file->vnode->fs; extern int elm_get_vol(FATFS * fat); RT_ASSERT(file->vnode->ref_count > 0); if (file->vnode->ref_count > 1) { if (file->vnode->type == FT_DIRECTORY && !(file->flags & O_DIRECTORY)) { return -ENOENT; } file->pos = 0; } if (fs == NULL) return -ENOENT; /* add path for ELM FatFS driver support */ vol = elm_get_vol((FATFS *)fs->data); if (vol < 0) return -ENOENT; drivers_fn = (char *)rt_malloc(256); if (drivers_fn == RT_NULL) return -ENOMEM; rt_snprintf(drivers_fn, 256, "%d:%s", vol, file->vnode->path);应该是FF_VOLUMES配置的问题
你那边走到了 (FF_VOLUMES > 1)里面所以没问题
我这里走的是另一个逻辑
[rt-thread/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c](https://github.com/RT-Thread/rt-thread/blob/6695599afcd365b0fe18e023c830b8260663f3cb/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c#L366-L368) Lines 366 to 368 in [6695599](/RT-Thread/rt-thread/commit/6695599afcd365b0fe18e023c830b8260663f3cb) #else drivers_fn = file->vnode->path; #endif这一块宏里面的逻辑判断或许应该统一一下,哈哈哈
RT_DFS_ELM_DRIVES 这个宏我看默认都是2,代表着FatFs 模块同时支持的最大逻辑驱动器(卷)数量,你那边是设置为了1吗?
@wdfk-prog 测试了下,还是没能复现 master分支,qemu-a9:
5.1.0分支:
- 有一个地方open该文件还为close的情况下,进行cat该文件吗?
- 可以在
if (file->vnode->ref_count > 1)里面加个打印看看是否直接退出了?int dfs_elm_close(struct dfs_file *file) { FRESULT result;
RT_ASSERT(file->vnode->ref_count > 0); if (file->vnode->ref_count > 1) { return 0; // <--- 此处直接返回,导致内存泄漏 } // ... 后续的释放逻辑 ...}
- 我看你打印的日子ret cnt:1 不知道是啥时候的情况
我就是在
if (file->vnode->ref_count > 1)这边加的打印,发现都是1,可以给个稳定复现的测试代码不?
- 我知道了
[rt-thread/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c](https://github.com/RT-Thread/rt-thread/blob/6695599afcd365b0fe18e023c830b8260663f3cb/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c#L338-L365) Lines 338 to 365 in [6695599](/RT-Thread/rt-thread/commit/6695599afcd365b0fe18e023c830b8260663f3cb) #if (FF_VOLUMES > 1) int vol; struct dfs_filesystem *fs = file->vnode->fs; extern int elm_get_vol(FATFS * fat); RT_ASSERT(file->vnode->ref_count > 0); if (file->vnode->ref_count > 1) { if (file->vnode->type == FT_DIRECTORY && !(file->flags & O_DIRECTORY)) { return -ENOENT; } file->pos = 0; } if (fs == NULL) return -ENOENT; /* add path for ELM FatFS driver support */ vol = elm_get_vol((FATFS *)fs->data); if (vol < 0) return -ENOENT; drivers_fn = (char *)rt_malloc(256); if (drivers_fn == RT_NULL) return -ENOMEM; rt_snprintf(drivers_fn, 256, "%d:%s", vol, file->vnode->path);- 应该是FF_VOLUMES配置的问题
- 你那边走到了 (FF_VOLUMES > 1)里面所以没问题
- 我这里走的是另一个逻辑
[rt-thread/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c](https://github.com/RT-Thread/rt-thread/blob/6695599afcd365b0fe18e023c830b8260663f3cb/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c#L366-L368) Lines 366 to 368 in [6695599](/RT-Thread/rt-thread/commit/6695599afcd365b0fe18e023c830b8260663f3cb) #else drivers_fn = file->vnode->path; #endif- 这一块宏里面的逻辑判断或许应该统一一下,哈哈哈
RT_DFS_ELM_DRIVES这个宏我看默认都是2,代表着FatFs 模块同时支持的最大逻辑驱动器(卷)数量,你那边是设置为了1吗?
- 是的,我修改为1了
#define RT_USING_DFS_ELMFAT
/* elm-chan's FatFs, Generic FAT Filesystem Module */
#define RT_DFS_ELM_CODE_PAGE 437
#define RT_DFS_ELM_WORD_ACCESS
#define RT_DFS_ELM_USE_LFN_3
#define RT_DFS_ELM_USE_LFN 3
#define RT_DFS_ELM_LFN_UNICODE_0
#define RT_DFS_ELM_LFN_UNICODE 0
#define RT_DFS_ELM_MAX_LFN 255
#define RT_DFS_ELM_DRIVES 1
#define RT_DFS_ELM_MAX_SECTOR_SIZE 4096
#define RT_DFS_ELM_REENTRANT
#define RT_DFS_ELM_MUTEX_TIMEOUT 3000
/* end of elm-chan's FatFs, Generic FAT Filesystem Module */
static void lfs_multi_open_repro_case(void)
{
int fd_primary = -1;
int fd_secondary = -1;
测试代码:
5.1.0分支: