我有一个 C 应用程序偶尔无法打开存储在共享上的文件/tmp
。
以下是相关代码块:
// open file and start parsing
notStdin = strcmp(inFile, "-");
if (notStdin) {
coordsIn = fopen(inFile, "r"); <----- inFile = file that I want to open
if (coordsIn == NULL) {
fprintf(stderr, "ERROR: Could not open coordinates file: %s\n\t%s\n", inFile, strerror(errno));
exit(EXIT_FAILURE);
}
}
else
coordsIn = stdin;
经过八到十次尝试后,我得到了一个NULL
FILE 指针。以下是错误消息示例:
ERROR: Could not open coordinates file: /tmp/coordinates.txt
File or directory does not exist
但是,该文件/tmp/coordinates.txt
确实存在,因为我可以使用head
、cat
或more
等标准实用程序打开它。
不同试用文件的权限/tmp/coordinates.txt
相同。
结果如下uname -a
:
$ uname -a
Linux hostname 2.6.18-128.2.1.el5 #1 SMP Wed Jul 8 11:54:47 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux
inFile
如果我使用存储在不同的、非共享中的不同的/tmp
,那么我就不会观察到这种症状。
有什么原因会导致共享fopen()
中存储的文件出现故障/tmp
?我还可以采取其他故障排除步骤吗?
答案1
打开的文件太多?
你的程序是否正在打开很多文件数量?也许您用完了文件描述符?以下是链接关于如何更改程序、shell 和操作系统(如果是这种情况)。要查看程序中使用的许多内容,请执行以下操作:
sudo lsof | grep <PID> | wc -l
在我的 Ubuntu 系统上,shell 限制为 1024,包括 stdout、stderr 和 stdin。这是在 /etc/security/limits.conf 中设置的。以下小程序显示了这一点:
#include <stdio.h>
int count=0;
int main( void ) {
while(1) {
FILE *fd = fopen("foo", "r");
if ( fd == NULL) {
printf("%i\n", count);
return(1);
}
count++;
}
return(0);
}
当我运行时,它会打印“1021”,退出状态为 1。
检查系统错误:
更一般地说,您可以随时检查 dmesg 或 /var/log/messages 的输出是否有任何错误。
查看文件,看看是否有其他东西干扰它:
也许该文件不存在,有什么东西正在从你这里删除它?你可能需要使用 inotify 监视所有事件在文件上,或者使用 inotify 的工具,例如因克龙或者inotify 工具。
答案2
也许某个程序锁定了这个文件?它可能是你的程序的另一个副本。
有lsof /tmp/coordinates.txt
显示什么吗?
答案3
我想不出 /tmp 有什么特殊之处,可以让文件间歇性地不存在。/tmp 只是一个普通目录,具有稍微特殊的权限,允许任何人乱搞,但限制非 root 用户不拥有文件以删除它们。
您的程序中是否有任何外部因素正在修改/更改该文件,或者您的程序是否是多线程的并且可以使用该文件?如果是这样,则可能是竞争条件。
要检查是否是这种情况,您可以按照 Kyle 的建议使用 inotify(您可能在删除并从事件中移出后)来查看文件到底发生了什么。
或者,您可以尝试统计文件并查看它的 ctime 和/或 mtime 是否与 fopen 因 ENOENT 而失败时相一致。
答案4
我不知道解决方案是什么,但我知道我观察到了同样的问题,而且不仅仅是在 /tmp 上。它可能发生在 NFS 挂载上,甚至本地挂载上,如 /lib。我今天发现的一个问题通过(错误地)打开、查找、读取一点并关闭同一个文件数千次(而不是在整个操作过程中保持文件打开)重现了这个问题。偶尔,其中一个 fopen() 会失败并出现 ENOENT 错误。这并不是像有人所说的那样打开了太多文件——它实际上认为文件一瞬间不存在。
我一直在寻找是否有人遇到过类似的问题,这是我遇到过最接近的问题。但我没有任何答案,只是在寻找解决方案。
我不认为这是 Linux(或 RHEL)所特有的,因为我没有在任何地方看到这种情况,只在一个环境中出现过。我不知道该环境有什么不同会导致这个问题(有区别)。不过,看到 RHEL5 中没有修复这个问题(我在 RHEL4 上看到了),这可不是什么好事。