在 CentOS 上调试 readdir(无论是 glibc 的 readdir(),还是内核里的 readdir 系统调用),常见方法如下,按“用户态 → 内核态”循序渐进。
先确认问题是否可复现:
#define _GNU_SOURCE
#include <dirent.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[]) {
DIR *dir = opendir(argv[1]);
if (!dir) {
perror("opendir");
return 1;
}
struct dirent *de;
while ((de = readdir(dir)) != NULL) {
printf("inode=%ld name=%s type=%d\n",
(long)de->d_ino, de->d_name, de->d_type);
}
if (errno) {
perror("readdir");
}
closedir(dir);
return 0;
}
编译:
gcc readdir_test.c -o readdir_test
运行:
./readdir_test /some/dir
strace 看系统调用(强烈推荐)strace -f -e trace=file ./readdir_test /path
或只看 readdir 相关:
strace -e trace=open,openat,getdents,getdents64,readdir ./readdir_test /path
重点看:
openat()getdents64()示例输出:
openat(AT_FDCWD, "/path", O_RDONLY|O_NONBLOCK|O_DIRECTORY) = 3
getdents64(3, /* 10 entries */, 32768) = 1234
gdb 单步调试gdb ./readdir_test
(gdb) break readdir
(gdb) run /path
如果 readdir 是 glibc 函数,可以:
catch syscall getdents64
安装调试符号:
debuginfo-install glibc
然后:
gdb ./readdir_test
(gdb) step
可进入 glibc 的 readdir 实现。
ls -la /path
stat /path
某些挂载选项会影响 readdir:
mount | grep /path
常见问题:
actimeo相关系统调用:
getdentsgetdents64函数路径(示例):
fs/readdir.c
-> vfs_readdir()
-> f_op->iterate / iterate_shared
ftrace 跟踪内核函数# 查看是否支持
cat /sys/kernel/debug/tracing/available_filter_functions | grep readdir
示例:
cd /sys/kernel/debug/tracing
echo function > current_tracer
echo vfs_readdir > set_ftrace_filter
echo 1 > tracing_on
# 执行程序
echo 0 > tracing_on
cat trace
perf 粗粒度分析perf trace -e getdents64 ./readdir_test /path
| 现象 | 可能原因 |
|---|---|
| readdir 返回 NULL 但 errno=0 | 目录读完(正常) |
| ENOTDIR | 路径不是目录 |
| EOVERFLOW | inode 太大(用 getdents64) |
| NFS 卡住 | 网络 / 挂载参数 |
| 顺序异常 | 文件系统不保证顺序 |
| overlayfs 丢文件 | lower/upper 合并问题 |
如果你愿意,可以告诉我:
cat /etc/redhat-release)mount)我可以直接给你针对性的调试命令或代码。