inotify_add_watch 返回-1需查errno:路径不存在/权限不足(ENOENT/EACCES)、达实例上限(EMFILE)、符号链接不可访问或文件系统不支持;务必立即检查errno定位根因。

inotify_add_watch 返回 -1 怎么定位原因
调用 inotify_add_watch 失败时,errno 才是关键线索,不是简单重试就能解决。常见原因有:
• 目录路径不存在或权限不足(ENOENT / EACCES)
• 已达到 per-user inotify instance 限制(EMFILE),可通过 /proc/sys/fs/inotify/max_user_instances 查看
• 监控路径是符号链接且未启用 IN_DONT_FOLLOW,而目标不可访问
• 文件系统不支持 inotify(极少见,如某些 FUSE 实现或只读挂载)
务必在失败后立刻检查 errno,例如:
int wd = inotify_add_watch(fd, "/path/to/dir", IN_CREATE | IN_MODIFY);<br>if (wd == -1) {<br> perror("inotify_add_watch failed"); // 自动打印 errno 对应字符串<br>}
IN_MOVED_TO 和 IN_CREATE 混用时为什么漏事件
Linux 内核对重命名操作(如 mv a b)触发的是 IN_MOVED_FROM + IN_MOVED_TO,而非 IN_CREATE;而文本编辑器保存常先写临时文件再 rename(),此时旧文件被删、新文件被“移动进来”。
若只监听 IN_CREATE,会完全错过这类更新。
正确做法是:
• 必须同时监听 IN_MOVED_TO(它覆盖了 rename 场景下的“新文件出现”)
• 若需区分新建与重命名,可结合 cookie 字段匹配 IN_MOVED_FROM 和 IN_MOVED_TO
• 不要依赖 IN_CREATE 判断“文件被创建”,它只对 open(O_CREAT) 或 mkdir() 等直接创建有效
read() 一次能取多少 inotify 事件
read() 从 inotify fd 读取的是变长结构体流,单次调用最多返回一个完整事件缓冲区(由内核 inotify 缓冲区大小决定,默认约 16KB),但**不会自动分片或合并多个事件**。
关键点:
• 每个 struct inotify_event 后紧跟可变长的 name[] 字段,必须用 event->len 计算下一个事件起始位置
• 若缓冲区不够存下完整事件(比如长文件名),内核会丢弃该事件并设置 IN_Q_OVERFLOW
• 建议分配至少 4KB 缓冲区,并循环解析直到 read() 返回 0 或小于 sizeof(struct inotify_event)
示例片段:
char buf[4096];<br>ssize_t len = read(inotify_fd, buf, sizeof(buf));<br>char *ptr = buf;<br>while (ptr < buf + len) {<br> struct inotify_event *e = (struct inotify_event *)ptr;<br> // 处理 e->name, e->mask 等<br> ptr += sizeof(struct inotify_event) + e->len;<br>}
监控子目录需要递归调用 inotify_add_watch 吗
inotify **本身不支持递归监控**,每个子目录都必须单独调用 inotify_add_watch 并获取独立 watch descriptor(wd)。
这意味着:
• 创建新子目录时,仅靠父目录的 IN_CREATE 事件无法自动开始监控它——你得自己 inotify_add_watch 新目录
• 删除子目录时,对应 wd 自动失效,无需手动 inotify_rm_watch,但你的程序需清理本地 wd 映射表
• 深层嵌套目录可能快速耗尽 max_user_watches(默认 8192),可通过 sysctl fs.inotify.max_user_watches=524288 临时提升
真正稳定的递归监控方案,要么用 fanotify(但仅限于可执行/写入等粗粒度事件),要么在用户态维护目录树 + wd 映射 + inotify 事件驱动的动态增删逻辑
立即学习“C++免费学习笔记(深入)”;



















