今天或过去30年的任何时候,它有多严重?
典型应用程序处理数据。它们消耗一些输入并产生结果。因此,在关闭只读文件和关闭刚生成或修改的文件时,可能会出现
close()
返回错误的两种情况。
已知的
close()
返回错误的情况都特定于将数据写入/刷新到永久存储器中。特别是,在实际写入永久存储器之前,操作系统通常会在本地缓存数据(在
close()
、
fsync()
或
fdatasync()
处);这在远程文件系统中非常普遍,这就是为什么NFS在man页面中提到的原因。
我从未遇到过关闭只读输入文件时出错的情况。我能想到的所有情况,即使使用任何常见的文件系统,在现实生活中可能发生的情况都是灾难性的失败,例如内核数据结构损坏。如果发生了这种情况,我认为
close()
错误不能是唯一表明出现了严重问题的迹象。
当在远程文件系统上写入文件时,如果本地网络容易出现故障或丢失大量数据包,则
close()
时间错误非常常见。作为最终用户,我希望我的应用程序告诉我在写入文件时是否出现错误。通常,与远程文件系统的连接完全中断,并且写入新文件失败是向用户发出的第一个指示器。
如果您不检查
close()
返回值,则应用程序将向用户撒谎。它将表明(如果没有其他情况下缺少错误消息),文件已正确编写,而实际上并非如此,并且应用程序被告知了这一点。应用程序只是忽略了这个指示。如果用户像我一样,他们会对应用程序感到非常不满意。
问题是,用户数据对您有多重要?大多数当前的应用程序员根本不关心。 Basile Starynkevitch(在原始问题的评论中)是绝对正确的;检查
close()
错误不是大多数程序员关心的事情。
我认为这种态度是可鄙的;对用户数据的漫不经心的无视。
尽管如此,这是自然的,因为用户无法明确指出哪个应用程序损坏了他们的数据。根据我的经验,最终用户最终会责怪操作系统、硬件、开源或免费软件,或者当地的IT支持;因此,对于程序员来说,没有任何社会压力或其他压力去关心这个问题。因为只有程序员了解这样的细节,而大多数程序员不关心,所以没有压力改变现状。
我知道说出上述内容会让很多程序员恨我,但至少我是诚实的。我指出这种情况时通常得到的反应是这种情况非常罕见,检查这种情况将是一种资源浪费。那可能是真的...但如果这意味着我的机器实际上更可预测,并告诉我它是否失去了重点,而不是默默地破坏我的数据,我愿意花更多的CPU周期和支付程序员几个百分点。
是否有一个简单、可重现的示例来证明这种静默数据丢失?
我知道三种方法:
使用USB驱动器,在最后一个write()
之后但在close()
之前拔出它。
不幸的是,大多数USB驱动器的硬件设计并不适合这样做,所以你可能会砖掉USB驱动器。
根据文件系统的不同,你的内核也可能会崩溃,因为大多数文件系统都是基于这种情况永远不会发生的假设编写的。
设置一个NFS服务器,并通过使用iptables来丢弃NFS服务器和客户端之间的所有数据包来模拟间歇性数据包丢失。
确切的情况取决于服务器和客户端、挂载选项和使用的版本。然而,使用两三个虚拟机设置测试环境应该相对容易。
使用自定义文件系统在close()
时间模拟写入错误。
当前内核不允许你强制卸载tmpfs或回环挂载,只有NFS挂载才能这样做,否则在最后一次写入但在close()
之前强制卸载文件系统将很容易模拟。(当前内核仅在该文件系统上有打开文件时拒绝umount。)
对于应用程序测试,创建一个返回错误的tmpfs变体close()
,如果文件模式表明它是可取的(例如,其他可写但不可读或可执行,即-??????-w-
)将是相当容易和安全的。它实际上不会破坏数据,但它可以方便地检查应用程序在内核报告(风险的)数据损坏时的行为。
close()
的返回值。根据Torvalds本人的说法,_"想要听到IO错误的'小心'用户必须真正执行fsync(),因此任何IO错误都应该在那里显示。当然,除了fsync()之外,还检查'close()'的返回值总是一个好主意"_。 - user986730